在WPF中实现可选的ComboBox枚举值

在开发WPF应用程序时,经常需要使用ComboBox控件来允许用户从一组预定义的选项中进行选择。有时,希望这些选项对应于枚举值,并且希望显示给用户的是枚举值的友好名称,而不是实际的枚举值。此外,可能还希望允许用户不进行任何选择,即支持空(null)选择。本文将介绍如何在不污染枚举定义的情况下,实现这样的ComboBox控件。

定义枚举和ViewModel

首先,定义一个枚举类型,用于表示可选的动物,并使用EnumMemberAttribute来指定每个枚举值的友好名称。

public enum Animals { [EnumMember(Value = "它是一只可爱的小猫")] Cat = 1, [EnumMember(Value = "它是一只活泼的小狗")] Dog = 2 } public class MainWindowViewModel : INPCBase { private Animals? selectedAnimal; public MainWindowViewModel() { SelectedAnimal = null; } public Animals? SelectedAnimal { get { return this.selectedAnimal; } set { RaiseAndSetIfChanged(ref this.selectedAnimal, value, () => this.SelectedAnimal); MessageBox.Show("SelectedAnimal: " + (!selectedAnimal.HasValue ? NullHelper.NullComboStringValue : selectedAnimal.ToString())); } } }

在ViewModel中,定义了一个可空的枚举类型的SelectedAnimal属性。当属性值改变时,通过MessageBox显示当前选中的动物,如果用户没有选择任何动物,则显示一个友好的提示信息。

定义View

接下来,定义XAML视图。使用ObjectDataProvider来提供枚举值,使用CompositeCollection来组合枚举值和一个特殊的"Null"值。同时,使用自定义的NullableEnumToFriendlyNameConverter来转换枚举值到友好名称,使用NullableEnumConverter来将用户的选择转换回枚举值或null。

<Window x:Class="NullEnumCombo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:nullEnumCombo="clr-namespace:NullEnumCombo" xmlns:sys="clr-namespace:System;assembly=mscorlib" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <ObjectDataProvider x:Key="animalTypeFromEnum" MethodName="GetValues" ObjectType="{x:Type sys:Enum}"> <ObjectDataProvider.MethodParameters> <x:Type TypeName="nullEnumCombo:Animals" /> </ObjectDataProvider.MethodParameters> </ObjectDataProvider> </Window.Resources> <Grid> <ComboBox Width="150" Height="20" HorizontalAlignment="Center" VerticalAlignment="Center" SelectedItem="{Binding SelectedAnimal, Converter={x:Static nullEnumCombo:NullableEnumConverter.Instance}, ConverterParameter={x:Static nullEnumCombo:Animals.Cat}}"> <ComboBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Path=., Mode=OneWay, Converter={x:Static nullEnumCombo:NullableEnumToFriendlyNameConverter.Instance}}" Height="Auto" Margin="0" VerticalAlignment="Center" /> </DataTemplate> </ComboBox.ItemTemplate> <ComboBox.ItemsSource> <CompositeCollection> <x:Static Member="nullEnumCombo:NullHelper.NullComboStringValue" /> <CollectionContainer Collection="{Binding Source={StaticResource animalTypeFromEnum}}" /> </CompositeCollection> </ComboBox.ItemsSource> </ComboBox> </Grid> </Window>

在XAML中,定义了一个ComboBox控件,它的ItemsSource绑定到一个CompositeCollection,其中包含了一个特殊的"Null"值和枚举值。ItemTemplate定义了ComboBox项的显示方式,使用NullableEnumToFriendlyNameConverter将枚举值转换为友好名称。SelectedItem绑定到ViewModel的SelectedAnimal属性,并使用NullableEnumConverter进行转换。

定义值转换器和辅助类

为了实现枚举值到友好名称的转换,定义了NullableEnumToFriendlyNameConverter值转换器。同时,为了将用户的选择转换回枚举值或null,定义了NullableEnumConverter值转换器。此外,定义了一个辅助类NullHelper,用于提供"Null"值的友好名称。

public class NullableEnumConverter : IValueConverter { private NullableEnumConverter() { } static NullableEnumConverter() { Instance = new NullableEnumConverter(); } public static NullableEnumConverter Instance { get; private set; } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null) { return NullHelper.NullComboStringValue; } return value; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { Type enumType = parameter.GetType(); if (value.ToString().Equals(NullHelper.NullComboStringValue)) { return null; } object rawEnum = Enum.Parse(enumType, value.ToString()); return System.Convert.ChangeType(rawEnum, enumType); } } [ValueConversion(typeof(object), typeof(String))] public class NullableEnumToFriendlyNameConverter : IValueConverter { private NullableEnumToFriendlyNameConverter() { } static NullableEnumToFriendlyNameConverter() { Instance = new NullableEnumToFriendlyNameConverter(); } public static NullableEnumToFriendlyNameConverter Instance { get; private set; } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value != null && !string.IsNullOrEmpty(value.ToString()) && !value.ToString().Equals(NullHelper.NullComboStringValue)) { FieldInfo fi = value.GetType().GetField(value.ToString()); if (fi != null) { var attributes = (EnumMemberAttribute[])fi.GetCustomAttributes(typeof(EnumMemberAttribute), false); return ((attributes.Length > 0) && (!String.IsNullOrEmpty(attributes[0].Value))) ? attributes[0].Value : value.ToString(); } } return NullHelper.NullComboStringValue; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new Exception("Can't convert back"); } } public class NullHelper { public static string NullComboStringValue { get { return "(无)"; } } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485