Есть VM со свойством типа enum.
Как вывести в ComboBox все значения из перечисления, так что бы выбранный элемент в ComboBox обновлял значение во ViewModel?
Допустим, у меня есть такой enum Этап:
enum Stage
{
First, Second, Third, Fourth
}
и в VM свойство такого типа:
Stage stage;
public Stage Stage
{
get => stage;
set => Set(ref stage, value);
}
В представлении я могу привязать текущий элемент ComboBoxа к этому свойству:
<ComboBox SelectedItem="{Binding Stage}"
ItemsSource="..."/>
остается как-то получить список всех значений Enum чтобы привязать их в ItemsSource. Я предлагаю сделать для этого небольшое расширение разметки:
class EnumExtension : MarkupExtension
{
public Type EnumType { get; set; }
public EnumExtension() { }
public EnumExtension(Type enumType) => EnumType = enumType;
public override object ProvideValue(IServiceProvider serviceProvider)
=> Enum.GetValues(EnumType);
}
Воспользуемся им:
ItemsSource="{c:Enum EnumType=c:Stage}"
или, благодаря наличию конструктора с параметром, еще короче:
ItemsSource="{c:Enum c:Stage}"
В принципе это уже работает, но в выпадающем списке выводятся строки First, Second и т.д., хочется привести их в нормальный человеческий вид.
Сделаем это с помощью конвертера:
class EnumToDescriptionConverter : IValueConverter
{
public IDictionary Dict { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var key = value?.ToString();
return Dict.Contains(key) ? Dict[key] : null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Dict.Cast<DictionaryEntry>().FirstOrDefault(p => p.Value == value).Key;
}
}
В этот конвертер через свойство можно внедрить нужный словарь, например, в зависимости от текущего языка.
Ну и немного модифицируем EnumExtension, чтобы также использовался конвертер:
class EnumExtension : MarkupExtension
{
public IValueConverter Converter { get; set; }
public Type EnumType { get; set; }
public EnumExtension() { }
public EnumExtension(Type enumType) => EnumType = enumType;
public override object ProvideValue(IServiceProvider serviceProvider)
=> Enum.GetValues(EnumType).Cast<ValueType>()
.Select(t => Converter?.Convert(t, EnumType, null, Thread.CurrentThread.CurrentUICulture) ?? t);
}
Остается только завести в ресурсах словарь, который будет сопоставлять каждое значение вашего Enum со строковым описанием, и передать его параметром в конвертер:
<FrameworkElement.Resources>
<col:Hashtable x:Key="Dict" xmlns:s="clr-namespace:System;assembly=mscorlib"
xmlns:col="clr-namespace:System.Collections;assembly=mscorlib">
<s:String x:Key="First">Первый этап</s:String>
<s:String x:Key="Second">Второй этап</s:String>
<s:String x:Key="Third">Третий этап</s:String>
<s:String x:Key="Fourth">Четвертый этап</s:String>
</col:Hashtable>
<c:EnumToDescriptionConverter x:Key="conv" Dict="{StaticResource Dict}"/>
</FrameworkElement.Resources>
Окончательная разметка вашего ComboBoxа:
<ComboBox SelectedItem="{Binding Stage, Converter={StaticResource conv}}"
ItemsSource="{c:Enum c:Stage, Converter={StaticResource conv}}"/>
Сборка персонального компьютера от Artline: умный выбор для современных пользователей