gpu blog


i18n (Интернационализация) в WPF и Silverlight. Числовые поля

Введение.
Представим себе что у нас есть число 1234,56 которое надо отобразить в нашем приложении в поле ввода или в гриде.
На компьютере с региональными настройками Америки, число должно отобразиться так:
1,234.56
На компьютере с региональными настройками Германии, число должно отобразиться так:
1.234,56

Проблема заключается в том что внутренние механизмы WPF и Silverlight не совсем правильно используют региональные настройки.


В интернете можно найти достаточно много решений, например:
Silverlight and Application Globalization – The Converter Approach
К сожалению данный вариант не позволяет решить проблему полностью.

Поскольку мне не удалось "выгуглить" метод, который бы позволял решить данную проблему в комплексе, предлагаю свой вариант решения для данной проблемы.

Решение для ВПФ.

1. Переопределениe мета информации у FrameworkElement.
        FrameworkElement.LanguageProperty.OverrideMetadata(GetType(FrameworkElement), New FrameworkPropertyMetadata(Markup.XmlLanguage.GetLanguage(Globalization.CultureInfo.CurrentCulture.IetfLanguageTag)))

Ето можно сделать в классе Application
    Protected Overrides Sub OnStartup(e As Windows.StartupEventArgs)
        FrameworkElement.LanguageProperty.OverrideMetadata(GetType(FrameworkElement), New FrameworkPropertyMetadata(Markup.XmlLanguage.GetLanguage(Globalization.CultureInfo.CurrentCulture.IetfLanguageTag)))
        MyBase.OnStartup(e)
    End Sub


2. Переопределение Binding
Используя MarkupExtensions создаем свой CustomBinding унаследованный от Binding и принудительно устанавливаем ConverterCulture в CultureInfo.CurrentCulture
В xaml-e используем CustomBinding вместо стандартного Binding там где ето оправдано, т.е. числовые поля.


3. Конвертер
Код конвертера достаточно тривиален, например:
    Public Class DoubleConverter
        Implements IValueConverter
        Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
            Dim dv As Double = CDbl(value)
            Dim frmtString As String = "N2"
            If parameter IsNot Nothing Then
                If TryCast(parameter, String) IsNot Nothing Then
                    frmtString = CStr(parameter)
                End If
            End If
            Return dv.ToString(frmtString, culture)
        End Function

        Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
            Dim ret As Double
            Dim stringValue As String = CStr(value)
            Dim style As NumberStyles = NumberStyles.Number
            Double.TryParse(stringValue, style, culture, ret)
            Return ret
        End Function
    End Class



И даже если мы поменяем региональные настройки.
Например:
десятичный разделитель заменить на #
тысячный на ?

То увидим что число 1234,56 будет отображаться как
1#234?56

И наоборот, если пользователь введет
2#987?01
то мы получим корректное число
2987,01


Решение для Silverlight

Решение аналогично с ВПФ, единственное метод FrameworkElement.LanguageProperty.OverrideMetadata нам не доступен
и CustomBinding наследуем от MarkupExtensions.
добавлено: 25 июн 14 просмотры: 947, комментарии: 0



Создание много модульных сборок. Часть 2

В предыдущей части ([url=]http://www.sql.ru/blogs/gpu_blog/1804[/url]) рассматривалось решение с доступом к исходникам.
Данная запись рассматривает решение без доступа к исходникам


Решение 2 (Наличие сборок)
Возникла необходимость создание .NET Assembly состоящей из нескольких модулей.
Используемые инструменты:

Компилятор (vbc.exe) и Ассемблер (ilasm.exe) находяться в
C:\Windows\Microsoft.NET\Framework\v4.0.30319
Линкер (al.exe) и дизассемблер (ildasm.exe) находяться в>
"C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools"

Исходные данные
Сборка Assembly1.dll, содержащая один класс Class1.
Сборка Assembly2.dll, содержащая один класс Class2.

Конечное приложение> App.vbproj
Imports Assembly1
Imports Assembly2
Class Application
    Public Sub New()
        Dim c1 As New Class1()
        c1.method()
        Dim c2 As New Class2()
        c2.method()
    End Sub
End Class

Конечное приложение имeет ссылки на Assembly1.dll и Assembly2.dll

Необходимо заменить ссылки на Assembly1.dll и Assembly2.dll на единственную ссылку, назовем ее AssemblyGate.dll
без изменения исходного кода ( Imports Assembly1)


1. Получаем IL Код
ildasm.exe Assembly1.dll /output:References\Assembly1.dll.il
ildasm.exe Assembly2.dll /output:References\Assembly2.dll.il

Cодержимое Assembly1.dll.il будет выглядеть как то так
+ IL Код

.assembly Assembly1
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )

// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )

.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
.custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 01 00 1A 2E 4E 45 54 46 72 61 6D 65 77 6F 72 6B // ....NETFramework
2C 56 65 72 73 69 6F 6E 3D 76 34 2E 30 01 00 54 // ,Version=v4.0..T
0E 14 46 72 61 6D 65 77 6F 72 6B 44 69 73 70 6C // ..FrameworkDispl
61 79 4E 61 6D 65 10 2E 4E 45 54 20 46 72 61 6D // ayName..NET Fram
65 77 6F 72 6B 20 34 ) // ework 4
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module Assembly1.dll
// MVID: {78BF4A04-E722-4E9D-BEE6-C00A5F2D8D4E}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0002 // WINDOWS_GUI
.corflags 0x00000001 // ILONLY
// Image base: 0x00660000


// =============== CLASS MEMBERS DECLARATION ===================
.class public auto ansi Assembly1.Class1
extends [mscorlib]System.Object
{
} // end of class Assembly1.Class1

// =============================================================

// *********** DISASSEMBLY COMPLETE ***********************


2. Редактирование IL кода
Удаляем секцию .assembly из IL кода и сохраняем изменения

3. Пересобираем Assembly1.dll и Assembly2.dll
ilasm.exe /output:References\Assembly1.dll /dll References\Assembly1.dll.il
ilasm.exe /output:References\Assembly2.dll /dll References\Assembly2.dll.il

4. Создаем Сборку
al.exe" /target:lib /out:References\AssemblyGate.dll References\Assembly1.dll References\Assembly2.dll

В директории References будут находиться 3 файла
Assembly1.dll (бинарный модуль 1)
Assembly2.dll (бинарный модуль 2)
AssemblyGate.dll (многомодульная сборка)

5. Изменяем конечное приложение
Удаляем проектные ссылки на сборки Assembly1 и Assembly2 и добавляем ссылку на AssemblyGate.dll
Компилируем проект.
Файлы Assembly1.dll, Assembly2.dll и AssemblyGate.dll будит скопированы в исполняемую директорию проекта.
Запускаем приложение и убеждаемся что все работает.
добавлено: 10 апр 14 просмотры: 688, комментарии: 0



Создание много модульных сборок. Часть 1

Возникла необходимость создание .NET Assembly состоящей из нескольких модулей.
Используемые инструменты:

Компилятор (vbc.exe) и Ассемблер (ilasm.exe) находяться в
C:\Windows\Microsoft.NET\Framework\v4.0.30319
Линкер (al.exe) и дизассемблер (ildasm.exe) находяться в>
"C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools"

Исходные данные
Проект Assembly1.vbproj (Root namespace Assembly1) состоящий из одного файла Class1.
Проект Assembly2.vbproj (Root namespace Assembly2) состоящий из одного файла Class2.

Конечное приложение> App.vbproj
Imports Assembly1
Imports Assembly2
Class Application
    Public Sub New()
        Dim c1 As New Class1()
        c1.method()
        Dim c2 As New Class2()
        c2.method()
    End Sub
End Class

Конечное приложение имeет ссылки на Assembly1.dll и Assembly2.dll

Необходимо заменить ссылки на Assembly1.dll и Assembly2.dll на единственную ссылку, назовем ее AssemblyGate.dll
без изменения исходного кода ( Imports Assembly1)

Решение 1 (Имеем доступ к исходникам)
1. Создаем модули
vbc.exe /t:module Assembly1\Class1.vb /out:References\Assembly1.dll
vbc.exe /t:module Assembly2\Class2.vb /out:References\Assembly2.dll

2. Создаем Сборку
al.exe" /target:lib /out:References\AssemblyGate.dll References\Assembly1.dll References\Assembly2.dll

В директории References будут находиться 3 файла
Assembly1.dll (бинарный модуль 1)
Assembly2.dll (бинарный модуль 2)
AssemblyGate.dll (многомодульная сборка)

Посмотрим на содержимое AssemblyGate.dll, для етого используем дизассемблер
ildasm.exe References\AssemblyGate.dll /output:References\1\AssemblyGate.dll.il
+ IL Код

---------------------------------------------------------------------------------
.file Assembly1.dll
.hash = (E7 06 DA 08 00 9B 70 69 90 02 0A E9 90 F3 67 90 // ......pi......g.
17 90 69 91 ) // ..i.
.file Assembly2.dll
.hash = (3D D2 8F D8 AA C4 B9 7B AC 28 94 CF F0 D0 B1 72 // =......{.(.....r
34 CB 1C 3C ) // 4..<
.class extern public Assembly1.Class1
{
.file Assembly1.dll
.class 0x02000002
}
.class extern public Assembly2.Class2
{
.file Assembly2.dll
.class 0x02000002
}
.module AssemblyGate.dll
// MVID: {D6FE70F4-4DC7-47D8-A2B6-7C7D0691A71A}
---------------------------------------------------------------------------------

Как видим сборка содержит внешние ссылки на классы, находящиеся в модулях Assembly1 и Assembly2

3. Изменяем конечное приложение
Удаляем проектные ссылки на сборки Assembly1 и Assembly2 и добавляем ссылку на AssemblyGate.dll
Компилируем проект.
Файлы Assembly1.dll, Assembly2.dll и AssemblyGate.dll будит скопированы в исполняемую директорию проекта.
Запускаем приложение и убеждаемся что все работает.
добавлено: 10 апр 14 просмотры: 648, комментарии: 0