2011-12-27 3 views
3

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

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 класса?

Update

Ну. Я нашел ответ в 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}}"/> 

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

+0

Вы можете связать свой combobox с int, а затем Enum.Parse (...) – Elastep

ответ

2

Если вы готовы чтобы изменить привязку ItemsSource ComboBox, тогда будет работать 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.

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

4

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

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

+0

Другой недостаток - это не очень хорошо работает для локализации, так как вам нужны строковые значения из ресурсов. –

Смежные вопросы