Enum в WPF ComboxBox с локализованными именами
У меня есть ComboBox с перечислением Enum.
enum StatusEnum {
Open = 1, Closed = 2, InProgress = 3
}
<ComboBox ItemsSource="{Binding StatusList}"
SelectedItem="{Binding SelectedStatus}" />
Я хочу отображать локализованные имена для значений перечисления на английском языке
Open
Closed
In Progress
но также и на немецком (и в других языках в будущем)
Offen
Geschlossen
In Arbeit
В моей модели ViewModel с помощью
public IEnumerable<StatusEnum> StatusList
{
get
{
return Enum.GetValues(typeof(StatusEnum)).Cast<StatusEnum>();
}
}
получает только имена перечисления в коде, а не переведенные.
У меня есть общая локализация на месте и вы можете получить к ним доступ, используя i.e.
Resources.Strings.InProgress
который возвращает мне перевод для текущего языка.
Как я могу автоматически привязать локализацию?
Ответы
Ответ 1
Это пример простого Enum
для переведенного строкового преобразователя.
public sealed class EnumToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{ return null; }
return Resources.ResourceManager.GetString(value.ToString());
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string str = (string)value;
foreach (object enumValue in Enum.GetValues(targetType))
{
if (str == Resources.ResourceManager.GetString(enumValue.ToString()))
{ return enumValue; }
}
throw new ArgumentException(null, "value");
}
}
Также вам понадобится MarkupExtension
, который предоставит значения:
public sealed class EnumerateExtension : MarkupExtension
{
public Type Type { get; set; }
public EnumerateExtension(Type type)
{
this.Type = type;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
string[] names = Enum.GetNames(Type);
string[] values = new string[names.Length];
for (int i = 0; i < names.Length; i++)
{ values[i] = Resources.ResourceManager.GetString(names[i]); }
return values;
}
}
Использование:
<ComboBox ItemsSource="{local:Enumerate {x:Type local:StatusEnum}}"
SelectedItem="{Binding SelectedStatus, Converter={StaticResource EnumToStringConverter}}" />
РЕДАКТИРОВАТЬ: Вы можете сделать более сложный преобразователь значений и расширение разметки. EnumToStringConverter
может использовать DescriptionAttribute
, чтобы получить переведенные строки. И EnumerateExtension
может использовать TypeConverter.GetStandardValues()
и конвертер. Это позволяет получать стандартные значения указанного типа (не только Enum
s) и преобразовывать их в строки или что-то другое в зависимости от преобразователя.
Пример:
<ComboBox ItemsSource="{local:Enumerate {x:Type sg:CultureInfo}, Converter={StaticResource CultureToNameConverter}}"
SelectedItem="{Binding SelectedCulture, Converter={StaticResource CultureToNameConverter}}" />
EDIT: Более сложное решение, описанное выше, опубликовано на GitHub.
Ответ 2
Вы не можете, из коробки.
Но вы можете создать свойство ObservableList<KeyValuePair<StatusEnum, string>>
и заполнить его своим перечислением/локализованным текстом, а затем привязать его к ComboBox
.
Что касается самой строки:
var localizedText = (string)Application.Current.FindResource("YourEnumStringName");
Получение строкового представления Enum с помощью методов Enum.GetName
/Enum.GetNames
.
Ответ 3
Вы можете использовать атрибут для перечисления и написать метод расширения для перечисления. См. Приведенный ниже код.
<ComboBox Width="200" Height="25" ItemsSource="{Binding ComboSource}"
DisplayMemberPath="Value"
SelectedValuePath="Key"/>
public class MainViewModel
{
public List<KeyValuePair<Status, string>> ComboSource { get; set; }
public MainViewModel()
{
ComboSource = new List<KeyValuePair<Status, string>>();
Status st=Status.Open;
ComboSource = re.GetValuesForComboBox<Status>();
}
}
public enum Status
{
[Description("Open")]
Open,
[Description("Closed")]
Closed,
[Description("InProgress")]
InProgress
}
public static class ExtensionMethods
{
public static List<KeyValuePair<T, string>> GetValuesForComboBox<T>(this Enum theEnum)
{
List<KeyValuePair<T, string>> _comboBoxItemSource = null;
if (_comboBoxItemSource == null)
{
_comboBoxItemSource = new List<KeyValuePair<T, string>>();
foreach (T level in Enum.GetValues(typeof(T)))
{
string Description = string.Empty;
FieldInfo fieldInfo = level.GetType().GetField(level.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes != null && attributes.Length > 0)
{
Description = GetDataFromResourceFile(attributes.FirstOrDefault().Description);
}
KeyValuePair<T, string> TypeKeyValue = new KeyValuePair<T, string>(level, Description);
_comboBoxItemSource.Add(TypeKeyValue);
}
}
return _comboBoxItemSource;
}
public static string GetDataFromResourceFile(string key)
{
//Do you logic to get from resource file based on key for a language.
}
}
Я уже опубликовал аналогичную вещь в SO Возможно ли связать привязку к Enum и показать удобные для пользователя значения?