Silverlight 正在将组合框绑定到枚举。。。在银光中!
因此,对于如何在WPF中将组合框绑定到枚举属性,web和StackOverflow有很多很好的答案。但是Silverlight缺少使这成为可能的所有功能:(。例如:Silverlight 正在将组合框绑定到枚举。。。在银光中!,silverlight,data-binding,xaml,enums,Silverlight,Data Binding,Xaml,Enums,因此,对于如何在WPF中将组合框绑定到枚举属性,web和StackOverflow有很多很好的答案。但是Silverlight缺少使这成为可能的所有功能:(。例如: 您不能使用接受类型参数的泛型样式IValueConverter,因为Silverlight不支持x:type 不能像中那样使用ObjectDataProvider,因为它在Silverlight中不存在 由于Silverlight中不存在标记扩展,因此不能使用来自#2的链接上的注释中的自定义标记扩展 您不能使用泛型而不是对象的Typ
IValueConverter
,因为Silverlight不支持x:type
ObjectDataProvider
,因为它在Silverlight中不存在Type
属性来实现#1的版本,因为XAML不支持泛型(使泛型工作的方法都依赖于标记扩展,Silverlight不支持)IValueConverter
class MyEnumConverter : GenericEnumConverter<MyEnum> {}
类MyEnumConverter:GenericEnumConverter{}
伙计们,你们的想法是什么?啊,我说得太快了!至少在Silverlight 3中有。(可能只有在3中,因为表明Silverlight 3中修复了与此相关的错误。) 基本上,
ItemsSource
属性需要一个转换器,但它可以是完全通用的,而不使用任何禁止的方法,只要您将类型为MyEnum
的属性的名称传递给它,并且将数据绑定到SelectedItem
完全没有痛苦;不需要转换器!好吧,至少它可以只要您不希望通过例如DescriptionAttribute
,为每个枚举值自定义字符串,嗯……可能需要另一个转换器;希望我能使其通用
更新:我制作了一个转换器,它可以工作!很遗憾,我现在必须绑定到SelectedIndex
,但没关系。请使用以下人员:
使用系统;
使用System.Collections.Generic;
使用系统组件模型;
使用System.Linq;
使用System.Windows.Data;
名称空间DomenicDenicola.Wpf
{
公共类EnumToIntConverter:IValueConverter
{
公共对象转换(对象值、类型targetType、对象参数、System.Globalization.CultureInfo区域性)
{
//注:正如Martin在对该答案的评论中指出的,这一行
//取决于从0开始按顺序排列的枚举值,
//因为组合框索引是这样做的。一个更通用的解决方案是
//可能会在GetValues数组中查找我们的值变量
//显示,然后返回该索引。
返回(int)值;
}
公共对象转换回(对象值、类型targetType、对象参数、System.Globalization.CultureInfo区域性)
{
返回Enum.Parse(targetType,value.ToString(),true);
}
}
公共类EnumToEnumerableConverter:IValueConverter
{
私有字典缓存=新字典();
公共对象转换(对象值、类型targetType、对象参数、System.Globalization.CultureInfo区域性)
{
var type=value.GetType();
如果(!this.cache.ContainsKey(类型))
{
var fields=type.GetFields().Where(field=>field.IsLiteral);
var值=新列表();
foreach(字段中的变量字段)
{
DescriptionAttribute[]a=(DescriptionAttribute[])字段。GetCustomAttributes(typeof(DescriptionAttribute),false);
如果(a!=null&&a.长度>0)
{
添加(a[0]。说明);
}
其他的
{
Add(field.GetValue(value));
}
}
this.cache[type]=值;
}
返回此.cache[type];
}
公共对象转换回(对象值、类型targetType、对象参数、System.Globalization.CultureInfo区域性)
{
抛出新的NotImplementedException();
}
}
}
使用这种绑定XAML:
<ComboBox x:Name="MonsterGroupRole"
ItemsSource="{Binding MonsterGroupRole,
Mode=OneTime,
Converter={StaticResource EnumToIEnumerableConverter}}"
SelectedIndex="{Binding MonsterGroupRole,
Mode=TwoWay,
Converter={StaticResource EnumToIntConverter}}" />
这种资源声明XAML:
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ddwpf="clr-namespace:DomenicDenicola.Wpf">
<Application.Resources>
<ddwpf:EnumToIEnumerableConverter x:Key="EnumToIEnumerableConverter" />
<ddwpf:EnumToIntConverter x:Key="EnumToIntConverter" />
</Application.Resources>
</Application>
任何评论都会被赏识,因为我有点是XAML/Silverlight /WPF/等新手。例如,<代码>枚举TimeTalver.TruttButt[/Case]会很慢,所以我应该考虑使用Cache?< /P> < P>有另一种方式将COMBOBOX绑定到枚举,而不需要为所选项目定制转换器。您可以在
检查它。它没有使用DescriptionAttributes…但它对我来说非常适合,所以我想这取决于它将被使用的场景。我发现简单封装枚举数据更容易使用
public ReadOnly property MonsterGroupRole as list(of string)
get
return [Enum].GetNames(GetType(GroupRoleEnum)).Tolist
End get
End Property
private _monsterEnum as GroupRoleEnum
Public Property MonsterGroupRoleValue as Integer
get
return _monsterEnum
End get
set(value as integer)
_monsterEnum=value
End set
End Property
这将完全消除对转换器的需要…:)这是Windows 8.1/Windows Phone通用应用程序的相同设置,主要更改如下:-
- 框架中缺少DescriptionAttribute(或者至少我找不到它)
- 反射工作方式的差异(使用TypeInfo.Declared字段)
<ComboBox x:Name="MonsterGroupRole"
ItemsSource="{Binding MonsterGroupRole,
Mode=OneTime}"
SelectedIndex="{Binding MonsterGroupRoleValue ,
Mode=TwoWay}" />
<ComboBox
ItemsSource="{Binding Path=MyProperty,Mode=OneWay, Converter={StaticResource EnumToIEnumerableConverter}}"
SelectedIndex="{Binding Path=MyProperty, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}"
/>
namespace MyApp.Converters
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Windows.UI.Xaml.Data;
public class EnumToIntConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
// Note: as pointed out by Martin in the comments on this answer, this line
// depends on the enum values being sequentially ordered from 0 onward,
// since combobox indices are done that way. A more general solution would
// probably look up where in the GetValues array our value variable
// appears, then return that index.
return (int) value;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value;
}
}
public class EnumToIEnumerableConverter : IValueConverter
{
private readonly Dictionary<TypeInfo, List<object>> _cache = new Dictionary<TypeInfo, List<object>>();
public object Convert(object value, Type targetType, object parameter, string language)
{
var type = value.GetType().GetTypeInfo();
if (!_cache.ContainsKey(type))
{
var fields = type.DeclaredFields.Where(field => field.IsLiteral);
var values = new List<object>();
foreach (var field in fields)
{
var a = (DescriptionAttribute[]) field.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (a != null && a.Length > 0)
{
values.Add(a[0].Description);
}
else
{
values.Add(field.GetValue(value));
}
}
_cache[type] = values;
}
return _cache[type];
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
[AttributeUsage(AttributeTargets.Field)]
public class DescriptionAttribute : Attribute
{
public string Description { get; private set; }
public DescriptionAttribute(string description)
{
Description = description;
}
}
}