c# - 将 ComboBox 的 SelectedValue 绑定(bind)到 WPF 中的枚举

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

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

public enum SelectionMode { One, Two }

和产品类:

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

    public string Name { get; set; }
}

ViewModel 类中,我有一个 ProductObservableCollection:

    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 和一个绑定(bind)到我的 ProductListListView:

<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>

我的问题是;将 ComboBoxSelectedValue 绑定(bind)到我的 Product 类的 SelectionMode 属性的方法是什么?

更新

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

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);
    }
}

并将其添加到窗口资源中:

<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}}"/>

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

最佳答案

这是我将枚举绑定(bind)到列表/组合框的用法

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" />

我的 View 模型

    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 来克服。我现在正在进行更改,完成后我会更新此答案。

关于c# - 将 ComboBox 的 SelectedValue 绑定(bind)到 WPF 中的枚举,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8644350/

相关文章:

c# - 用于 Windows 8 开发的 Metro 与 WPF?

c# - 为什么这个例子中的队列锁是必要的

wpf - 你如何在 .xaml 文件中使用 stylecop

c# - 如何在 xaml 中创建 ListView 项

c# - Xamarin.Forms Shell 在视觉层次结构之外导航

c# - Entity Framework 不加载相关对象

c# - 加载lucene索引中的一个字段

WPF 使用自定义 RoutedUICommands 还是简单的事件处理程序?

c# - 如何根据窗口更改对话框消息?

WPF 将绑定(bind)值从整数更改为图像