Привязка SelectedValue ComboBox к перечислению в WPF - PullRequest
3 голосов
/ 27 декабря 2011

Я хочу показать список продуктов в ListView, где один из столбцов - это ComboBox, который я хочу связать.Это мое перечисление:

public enum SelectionMode { One, Two }

И Класс продукта:

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

    public string Name { get; set; }
}

В ViewModel классе у меня ObservableCollection из Product 's:

    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 с ListView, который связывается с моим ProductList:

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

и добавить его в ресурсы окна:

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

Это все.Надеюсь, это будет полезно для кого-то еще:)

Ответы [ 3 ]

4 голосов
/ 04 декабря 2013

Вот мое использование привязки перечислений к списку / 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;
    }
}

По моему личному мнению, он намного чище и пригоден для многократного использования.Единственный недостаток, который я обнаружил, это то, что если вы обновляете выбранное значение в коде (не через пользовательский интерфейс), то оно не обновляется в пользовательском интерфейсе.Но это можно преодолеть с помощью дальнейшей настройки пользовательского интерфейса.Сейчас я делаю изменения и обновлю этот ответ, как только закончу.

2 голосов
/ 27 декабря 2011

Если вы готовы изменить привязку ItemsSource ComboBox, тогда просто SelectedValue="{Binding Mode,UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" будет работать.

В этом случае вы должны связать ItemSource следующим образом: ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ViewClass}}, Path=ModeList}"; где ModeList - это простое открытое свойство списка типа SelectionMode, содержит перечисления, которые должны отображаться в раскрывающемся списке ComboBox, а ViewClass - это класс, где это свойство (ModeList) доступно; убедитесь, что ссылка на пространство имен добавлена ​​в xaml.

В противном случае вы должны использовать конвертер, который должен преобразовать строку в тип enum.

1 голос
/ 27 декабря 2011

Для этого я использую конвертер, который также позволяет определить строку, которая будет отображаться вместо значения перечисления: http://www.ageektrapped.com/blog/the-missing-net-7-displaying-enums-in-wpf/

...