Конвертер для отображения описания перечисления и преобразования обратно в значение перечисления при выборе элемента из поля со списком в wpf
Я использую перечисление, чтобы заручиться значениями в моем combobox. Я хочу написать конвертер, который покажет "описание" выбранного значения перечисления. И при выборе он вернет значение перечисления.
большинство конвертеров онлайн не реализовали метод ConvertBack () (именно поэтому я публикую здесь).
спасибо заранее.
5 ответов
вот метод ConvertBack:
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
Полный Код Конвертера:
public class EnumConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null) return DependencyProperty.UnsetValue;
return GetDescription((Enum)value);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
public static string GetDescription(Enum en)
{
Type type = en.GetType();
MemberInfo[] memInfo = type.GetMember(en.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs != null && attrs.Length > 0)
{
return ((DescriptionAttribute)attrs[0]).Description;
}
}
return en.ToString();
}
}
редактировать
вот мой XAML ComboBox:
<ComboBox ItemsSource="{Binding SampleValues}"
SelectedItem="{Binding SelectedValue, Converter={StaticResource enumConverter}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=., Converter={StaticResource enumConverter}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
EDIT 2:
у меня изначально был неправильный XAML, я был привязан SelectedValue
to ComboBox.SelectedIndex
, вместо ComboBox.SelectedItem
. Вот почему я должен был использовать Enum.ToObject
в своем ConvertBack
метод. После исправления XAML и запуска образца через отладчик I понял, что могу просто вернуться!--8--> С ConvertBack
метод, потому что само значение Enum
тип.
Я знаю, что это старый вопрос, но по какой-то причине это довольно сложно, хотя кажется, что это довольно распространенная задача (в настоящее время я делаю это в приложении UWP). Используя комбинацию принятого ответа, некоторые другие предметы, которые я нашел, и немного моей собственной работы, вот самый простой способ выполнить эту черную задачу. Короче:
- определите перечисление вместе с настройкой описания в атрибуте отображения
- создать конвертер это преобразует значение перечисления в описание
- в viewmodel, выставить коллекцию значений перечисления, из которых выбрать, выбранное значение перечисления, а затем инициализировать те
- определите пару удобных методов расширения перечисления
- Наконец, некоторые простые привязки к ComboBox, просто переопределяя его ItemTemplate использовать конвертер.
перечисление
public enum EnumOptions
{
[Display(Description = "Option 1")]
OptionOne= 1,
[Display(Description = "Option 2")]
OptionTwo,
[Display(Description = "Option 3")]
OptionThree
}
конвертер
public class EnumToDisplayConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var enumValue = value as Enum;
return enumValue == null ? DependencyProperty.UnsetValue : enumValue.GetDescriptionFromEnumValue();
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value;
}
}
Viewmodel (частично)
public IReadOnlyList<EnumOptions> Options { get; }
private EnumOptions _selectedOption;
public EnumOptions SelectedOption
{
get { return _selectedOption; }
set
{
_selectedOption = value;
OnPropertyChanged(() => SelectedOption);
}
}
// Initialization in constructor
Options = EnumExtensions.GetValues<EnumOptions>().ToArray();
// If you want to set a default.
SelectedOption = Options[0];
расширения
public static class EnumExtensions
{
public static string GetDescriptionFromEnumValue(this Enum value)
{
var attribute = value.GetType()
.GetField(value.ToString())
.GetCustomAttributes(typeof(DisplayAttribute), false)
.SingleOrDefault() as DisplayAttribute;
return attribute == null ? value.ToString() : attribute.Description;
}
/// <summary>
/// Enumerates all enum values
/// </summary>
/// <typeparam name="T">Enum type</typeparam>
/// <returns>IEnumerable containing all enum values</returns>
/// <see cref="http://stackoverflow.com/questions/972307/can-you-loop-through-all-enum-values"/>
public static IEnumerable<T> GetValues<T>()
{
return Enum.GetValues(typeof (T)).Cast<T>();
}
}
XAML (частично)
<TextBlock Grid.Row="1">Choose an option</TextBlock>
<ComboBox Grid.Row="2"
ItemsSource="{Binding Options}"
SelectedItem="{Binding SelectedOption, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource EnumToDisplayConverter}}"></TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
[ValueConversion(typeof(MyEnum), typeof(String))]
public class MyEnumConverter : IValueConverter
{
public object Convert(object value,
Type targetType,
object parameter,
CultureInfo culture)
{
var enumVal = (MyEnum)value;
// in this example, this is an extension method
return enumValue.Description();
}
public object ConvertBack(object value,
Type targetType,
object parameter,
CultureInfo culture)
{
var enumDesc = value as string;
MyEnum val;
if (Enum.TryParse(typeof(MyEnum), strValue, out val))
{
return val;
}
return DependencyProperty.UnsetValue;
}
}
метод расширения в Примере может выглядеть так:
public static string Description(this MyEnum enumVal)
{
// you could use a switch statement here;
// or maybe a Dictionary
}
дополнение к приведенным выше примерам, чтобы показать украшение перечисления атрибутами.
sealed class DescriptionAttribute : Attribute
{
readonly string description;
public DescriptionAttribute(string description)
{
this.description = description;
}
public string Description
{
get { return description; }
}
}
enum Vehicle
{
[Description("Benz")]
Car,
[Description("Volvo")]
Bus,
[Description("Honda")]
Bike
}
кстати, интересно, почему вам нужно было преобразовать описание в перечисление. Если вы предоставляете перечисления как ItemSource, вы можете использовать метод описания, чтобы показать отображаемое значение в ComboBox, однако, как только элемент выбран, вы можете напрямую иметь перечисление как выбранный элемент.
вот мой рабочий пример:
перечисление определение:
public enum MyEnum
{
[Description("Exchange 2007")]
E2007,
[Description("Exchange 2010")]
E2010,
[Description("Exchange 2013")]
E2013,
};
вспомогательный класс:
public static class cHelperClass
{
#region GetValuesAndDescriptions
public static object[] GetValuesAndDescriptions(Type enumType)
{
var kvPairList = new List<KeyValuePair<string, string>>();
var listValue = Enum.GetValues(enumType);
for (var i = 0; i < listValue.Length; i++)
{
var value = listValue.GetValue(i);
var enumValue = (Enum)listValue.GetValue(i);
kvPairList.Add(new KeyValuePair<string, string>(value.ToString(), GetDescription(enumValue)));
}
var valuesAndDescriptions = from kv in kvPairList select new
{
Value = kv.Key,
Description = kv.Value
};
return valuesAndDescriptions.ToArray();
}
public static string GetDescription(this Enum value)
{
var fieldInfo = value.GetType().GetField(value.ToString());
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
return (attributes.Length > 0) ? attributes[0].Description : value.ToString();
}
public static string GetStringValue(this Enum enumItem)
{
return enumItem
.GetType()
.GetField(enumItem.ToString())
.GetCustomAttributes<StringValueAttribute>()
.Select(a => a.Value)
.FirstOrDefault() ?? enumItem.ToString();
}
public static string GetName(Type enumType, object value)
{
return Enum.GetName(enumType, value);
}
#endregion
}
XAML:
<UserControl.Resources>
<!-- ObjectDataProvider für WindowStyles -->
<ObjectDataProvider x:Key="myEnumResource" MethodName="GetValuesAndDescriptions" ObjectType="classes:cHelperClass">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="classes:MyEnum" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</UserControl.Resources>
<ComboBox ItemsSource="{Binding Source={StaticResource myEnumResource}}" DisplayMemberPath="Description" SelectedValuePath="Value" SelectedValue="{Binding MyEnum, Mode=TwoWay}" />