Использование перечислений (enum) в WPF очень удобно. Например, можно продекларировать в XAML указать, что поля перечисления надо использовать для наполнения ComboBox, и в выпадающем списке появятся текстовые представления полей перечисления.
Для этого в ресурсах надо объявить ObjectDataProvider, который обратится к методу Enum.GetValues:
<ObjectDataProvider x:Key="IntervalList"
ObjectType="{x:Type s:Enum}"
MethodName="GetValues">
<ObjectDataProvider.MethodParameters>
<x:Type Type="{x:Type m:ProblemDiagnosticInterval}"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
и непосредственно в ComboBox указать объявленный объект в качестве источника данных:
<ComboBox HorizontalAlignment="Stretch" x:Name="IntervalBox"
SelectedValue="{Binding Value.Interval}"
ItemsSource="{Binding Source={StaticResource IntervalList}}" />
И в выпадающем списке появятся значения из перечисления:
public enum ProblemDiagnosticInterval
{
Never,
TwoWeeks,
OneMonth,
ThreeMonth,
Unlimited
}
Казалось бы, все замечательно. Но только до тех пор пока не потребуется переводить интерфейс приложения на другие языки. Я хочу поделиться способом, который позволяет использовать все преимущества использования перечислений и при этом в интерфейсе отображаются строки, соответствующие текущему языку приложения.
Я уже описывал технологию локализации WPF приложений. Дальнейшее изложение опирается на этот материал.
Чтобы управлять текстом, который отображается вместо поля перечисления необходимо завести простой класс-конвертер типов, связанный с этим перечислением:
[TypeConverter(typeof(EnumToResourceStringConverter))]
public enum ProblemDiagnosticInterval
{
...
}
/// <summary>
/// переопределяет для перечислений конвертацию
/// в строку из ресурсника приложения
/// </summary>
public class EnumToResourceStringConverter : TypeConverter
{
public static IStringResourceAccessor ResourceAccessor { get; set; }
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType.Equals(typeof(Enum)))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType.Equals(typeof(string)))
return true;
return base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (value != null && destinationType.Equals(typeof(string)))
{
var originValue = (string)base.ConvertTo(context, culture, value, destinationType);
var typeName = value.GetType().Name;
return ResourceAccessor.GetStringByID(typeName + "_" + originValue);
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
Этот конвертер реализует преобразование элемента перечисления в строку, используя обращение к объекту, реализующему доступ к локализованным строками через интерфейс IStringResourceAccessor.
public interface IStringResourceAccessor
{
string GetStringByID(string stringID);
}
В качестве идентификатора строки в ресурсах передается строка вида <имя перечисления>_<имя элемента перечисления>, например, в описываемом примере это будут строки ProblemDiagnosticInterval_Never, ProblemDiagnosticInterval_TwoWeeks и т.д.Статическое свойство, в котором хранится указатель на интерфейс доступа к ресурсам инициализируется, например, в конструкторе класса приложения:
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application, IStringResourceAccessor
{
public App(string[] args)
{
...
EnumToResourceStringConverter.ResourceAccessor = this;
...
}
...
public static string RString(string name)
{
try
{
return Application.Current.Resources[name].ToString();
}
catch (System.Exception)
{
return "load string " + name + " failed";
}
}
#region IStringResourceAccessor Members
public string GetStringByID(string stringID)
{
return App.RString(stringID);
}
#endregion
}
После этого необходимо в одном из XAML объявить строки с правильными идентификаторами, которые будут использованы в для показа полей перечисления:
<!-- названия интервалов диагностирования проблем -->
<core:StringObject x:Key="ProblemDiagnosticInterval_Never" Localization.Attributes="Value (Readable Modifiable Text)" Value="Скрыть" />
<core:StringObject x:Key="ProblemDiagnosticInterval_TwoWeeks" Localization.Attributes="Value (Readable Modifiable Text)" Value="2 недели" />
<core:StringObject x:Key="ProblemDiagnosticInterval_OneMonth" Localization.Attributes="Value (Readable Modifiable Text)" Value="1 месяц" />
<core:StringObject x:Key="ProblemDiagnosticInterval_ThreeMonth" Localization.Attributes="Value (Readable Modifiable Text)" Value="3 месяца" />
<core:StringObject x:Key="ProblemDiagnosticInterval_Unlimited" Localization.Attributes="Value (Readable Modifiable Text)" Value="Все" />
Текстовые значения для других языков указываются в отдельном файле в соответствии с технологией локализации.
И вот результат этих манипуляций:
Комментариев нет:
Отправить комментарий