在WPF应用程序开发中,经常需要处理各种数据绑定的场景,尤其是涉及到枚举类型的数据。当枚举类型可以为空时,就需要一种方法来处理这种情况。本文将介绍如何在WPF中使用ComboBox控件与可空枚举进行绑定,并展示相关的XAML和C#代码实现。
首先,需要创建一个ViewModel,它将作为数据模型。在这个ViewModel中,将定义一个可空的枚举类型的属性。
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace WpfApplication1
{
public enum ProductType
{
[Description("湿粮")]
WetFood = 1,
[Description("干粮")]
DryFood = 2
}
public class MainWindowViewModel : INotifyPropertyChanged
{
private ProductType? selectedProductType;
public ProductType? SelectedProductType
{
get { return selectedProductType; }
set
{
selectedProductType = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(
[CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
在上面的代码中,定义了一个名为ProductType的枚举,它有两个成员:WetFood和DryFood。还定义了一个MainWindowViewModel类,它实现了INotifyPropertyChanged接口,以便在属性值发生变化时通知UI进行更新。SelectedProductType属性是一个可空的ProductType枚举类型。
接下来,需要在XAML中定义UI。将使用ComboBox控件来显示枚举类型的值,并允许用户选择。
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ObjectDataProvider x:Key="ProductTypeEnumProvider" MethodName="GetValues" ObjectType="{x:Type sys:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:ProductType" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
<Grid>
<ComboBox HorizontalAlignment="Center" VerticalAlignment="Center" SelectedItem="{Binding SelectedProductType, Converter={x:Static local:NullableEnumConverter.Instance}, ConverterParameter={x:Static local:ProductType.DryFood}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=., Mode=OneWay, Converter={x:Static local:NullableEnumToFriendlyNameConverter.Instance}}" Height="Auto" Margin="0" VerticalAlignment="Center" />
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemsSource>
<CompositeCollection>
<x:Static Member="local:NullHelper.NullComboStringValue" />
<CollectionContainer Collection="{Binding Source={StaticResource ProductTypeEnumProvider}}" />
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
</Grid>
</Window>
在上面的XAML代码中,定义了一个ComboBox控件,并使用了一个ObjectDataProvider来获取枚举类型的所有值。还定义了一个ItemTemplate,用于显示每个枚举值的友好名称。ComboBox的ItemsSource属性被设置为一个CompositeCollection,它允许将不同的数据源组合在一起。
为了使ComboBox能够正确显示枚举值的友好名称,需要定义一些辅助类和值转换器。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WpfApplication1
{
public class NullHelper
{
public static string NullComboStringValue
{
get { return "无"; }
}
}
}
NullHelper类提供了一个静态属性NullComboStringValue,它返回一个字符串"无",用于表示ComboBox中的空选项。
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows.Data;
namespace WpfApplication1
{
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);
}
}
}
NullableEnumConverter类实现了IValueConverter接口,用于将可空枚举值转换为友好名称。如果枚举值为空,则返回NullHelper类中定义的字符串。
using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Windows.Data;
namespace WpfApplication1
{
[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 = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
return ((attributes.Length > 0) && (!String.IsNullOrEmpty(attributes[0].Description))) ? attributes[0].Description : value.ToString();
}
}
return NullHelper.NullComboStringValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new Exception("Can't convert back");
}
}
}