[英]Binding SelectedValue of ComboBox to enum in WPF
我想在ListView
中顯示產品列表,其中一列是我想要綁定的ComboBox
。 這是我的枚舉:
public enum SelectionMode { One, Two }
和產品類:
public class Product
{
public SelectionMode Mode { get; set; }
public string Name { get; set; }
}
在ViewModel
類中,我有一個Product
的ObservableCollection
:
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"}
};
}
最后我有一個帶有ListView
的Grid
,它綁定到我的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>
我的問題是; 將ComboBox
SelectedValue
綁定到Product
類的SelectionMode
屬性的方法是什么?
更新
好。 我在這個主題中找到了答案。 所以我必須添加轉換器類:
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}}"/>
就這樣。 希望它對別人有用:)
下面我將綁定枚舉用於列表/ 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調整來克服。 我現在正在進行更改,一旦完成,我將更新此答案。
如果您准備更改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中添加了名稱空間的引用。
否則你必須使用轉換器,它應該將字符串轉換回枚舉類型。
我正在使用轉換器,它還允許定義將顯示的字符串而不是枚舉值: http : //www.ageektrapped.com/blog/the-missing-net-7-displaying-enums-在-WPF /
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.