将ComboBox的SelectedValue绑定到WPF中的枚举

时间:2011-12-27 11:56:18

标签: c# wpf xaml data-binding wpf-controls

我想在ListView中显示产品列表,其中一列是我要绑定的ComboBox。这是我的枚举:

public enum SelectionMode { One, Two }

和产品类:

public class Product
{
    public SelectionMode Mode { get; set; }

    public string Name { get; set; }
}

ViewModel课程中,我有ObservableCollectionProduct

    private ObservableCollection<Product> _productList;
    public ObservableCollection<Product> ProductList
    {
        get
        {
            return _productList;
        }
        set
        {
            _productList = value;
        }
    }

    public MainViewModel()
    {
        ProductList = new ObservableCollection<Product>
                          {
                              new Product {Mode = SelectionMode.One, Name = "One"},
                              new Product {Mode = SelectionMode.One, Name = "One"},
                              new Product {Mode = SelectionMode.Two, Name = "Two"}
                          };
    }

最后我有Grid ListViewProductList绑定:

<Window.Resources>
    <ObjectDataProvider x:Key="AlignmentValues" 
                    MethodName="GetNames" ObjectType="{x:Type System:Enum}">
        <ObjectDataProvider.MethodParameters>
            <x:Type TypeName="ViewModel:SelectionMode" />
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Window.Resources>

<Grid>
    <ListView Height="120" HorizontalAlignment="Left" 
                  VerticalAlignment="Top"
                  SelectionMode="Multiple" 
                  ItemsSource="{Binding ProductList}" >
        <ListView.View>
            <GridView>
                <GridViewColumn Width="120" Header="Product Name" DisplayMemberBinding="{Binding Path=Name}" />
                <GridViewColumn Header="Selection Mode">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <ComboBox ItemsSource="{Binding Source={StaticResource AlignmentValues}}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
            </GridView>
        </ListView.View>
    </ListView>
</Grid>

我的问题是;将SelectedValue类的ComboBox SelectionMode Product属性绑定到public class MyEnumToStringConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return value.ToString(); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return (SelectionMode)Enum.Parse(typeof(SelectionMode), value.ToString(), true); } } 的属性的方法是什么?

更新

好。我在this topic找到了答案。所以我必须添加转换器类:

<Window.Resources>
    <ObjectDataProvider x:Key="AlignmentValues" 
                    MethodName="GetNames" ObjectType="{x:Type System:Enum}">
        <ObjectDataProvider.MethodParameters>
            <x:Type TypeName="ViewModel:SelectionMode" />
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
    <Converters:MyEnumToStringConverter x:Key="MyEnumConverter"/>
</Window.Resources>

并将其添加到窗口资源:

ComboBox

最后编辑<ComboBox ItemsSource="{Binding Source={StaticResource AlignmentValues}}" SelectedValue="{Binding Path=Mode, Converter={StaticResource MyEnumConverter}}"/> 数据模板:

{{1}}

这就是全部。 希望它对其他人有用:)

3 个答案:

答案 0 :(得分:4)

继承我对绑定枚举的使用到列表/ combox

public enum EnumsAvailable
{
    [Description("Its an A")]
    a,
    [Description("Its a B")]
    b,
    [Description("Its a C")]
    c,
    [Description("Its a D")]
    d
} ;

这是我的XAML

        <ComboBox Grid.Column="4" Grid.Row="0" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="cb_Application" VerticalAlignment="Top" Width="120"
              ItemsSource="{Binding Path=ListOfEnumValues,Converter={converters:ArrayStringToEnumDescriptionConverter}}"
              SelectedValue="{Binding Path=ChosenEnum,Converter={converters:DescriptionToEnumConverter},UpdateSourceTrigger=PropertyChanged}"
              Validation.ErrorTemplate="{x:Null}" TabIndex="5" />

我的视图模型

    public EnumsAvailable ListOfEnumValues
    {
        get { return new EnumsAvailable(); }
    }

    public EnumsAvailable ChosenEnum { 
        get { return _ChosenEnum; }
        set
        {
            if (_ChosenEnum != value)
            {
                _ChosenEnum = value;
                RaisePropertyChanged(() => ChosenEnum);
            }
        } 
    }

和我的转换器

public class ArrayStringToEnumDescriptionConverter : BaseEnumDescriptionConverter, IValueConverter
{
    public ArrayStringToEnumDescriptionConverter()
    {

    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var type = value.GetType();
        return !type.IsEnum ? null : base.GetEnumDescription(type);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}

public abstract class BaseEnumDescriptionConverter : MarkupExtension
{
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }

    public IEnumerable<string> GetEnumDescription(Type destinationType)
    {
        var enumType = destinationType;

        var values = RetrieveEnumDescriptionValues(enumType);

        return new List<string>(values);
    }

    public object GetEnumFromDescription(string descToDecipher, Type destinationType)
    {
        var type = destinationType;
        if (!type.IsEnum) throw new InvalidOperationException();
        var staticFields = type.GetFields().Where(fld => fld.IsStatic);
        foreach (var field in staticFields)
        {
            var attribute = Attribute.GetCustomAttribute(field,
                typeof(DescriptionAttribute)) as DescriptionAttribute;
            if (attribute != null)
            {
                if (attribute.Description == descToDecipher)
                {
                    return (Enum.Parse(type, field.Name, true));
                }
            }
            else
            {
                if (field.Name == descToDecipher)
                    return field.GetValue(null);
            }
        }
        throw new ArgumentException("Description is not found in enum list.");
    }

    public static string[] RetrieveEnumDescriptionValues(Type typeOfEnum)
    {
        var values = Enum.GetValues(typeOfEnum);

        return (from object fieldInfo in values select DescriptionAttr(fieldInfo)).ToArray();
    }



    public static string DescriptionAttr(object enumToQuery)
    {
        FieldInfo fi = enumToQuery.GetType().GetField(enumToQuery.ToString());

        DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(
            typeof(DescriptionAttribute), false);

        return attributes.Length > 0 ? attributes[0].Description : enumToQuery.ToString();
    }

    public static string GetDomainNameAttribute(object enumToQuery)
    {
        FieldInfo fi = enumToQuery.GetType().GetField(enumToQuery.ToString());

        DomainNameAttribute[] attributes = (DomainNameAttribute[])fi.GetCustomAttributes(
            typeof(DomainNameAttribute), false);

        return attributes.Length > 0 ? attributes[0].DomainName : enumToQuery.ToString();
    }

}

public class DescriptionToEnumConverter : BaseEnumDescriptionConverter, IValueConverter
{
    public DescriptionToEnumConverter(){}

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var enumValue = value;

        if (enumValue != null)
        {
            enumValue = GetEnumFromDescription(value.ToString(), targetType);
        }

        return enumValue;
    }
}

在我个人看来,它更清洁,高度可重复使用。到目前为止,我发现的唯一缺陷是,如果您更新代码中的选定值(不是通过UI),那么它不会在UI上更新。但是这可以通过进一步的UI调整来克服。我现在正在进行更改,一旦完成,我将更新此答案。

答案 1 :(得分:2)

如果您准备更改ComboBox的ItemsSource的绑定,那么只需SelectedValue="{Binding Mode,UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"即可。

在这种情况下,您必须像这样绑定ItemsSource:ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ViewClass}}, Path=ModeList}";其中,ModeList是SelectionMode类型列表的简单公共属性,包含应该在ComboBox下拉列表中显示的枚举,而ViewClass是此属性(ModeList)可用的类;确保在xaml中添加了名称空间的引用。

否则你必须使用转换器,它应该将字符串转换回枚举类型。

答案 2 :(得分:1)

我正在使用转换器,它还允许定义将显示的字符串而不是枚举值:http://www.ageektrapped.com/blog/the-missing-net-7-displaying-enums-in-wpf/