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

因此,对于如何在WPF中将组合框绑定到枚举属性,web和StackOverflow有很多很好的答案。但是Silverlight缺少使这成为可能的所有功能:(。例如:

  • 您不能使用接受类型参数的泛型样式
    IValueConverter
    ,因为Silverlight不支持
    x:type
  • 不能像中那样使用
    ObjectDataProvider
    ,因为它在Silverlight中不存在
  • 由于Silverlight中不存在标记扩展,因此不能使用来自#2的链接上的注释中的自定义标记扩展
  • 您不能使用泛型而不是对象的
    Type
    属性来实现#1的版本,因为XAML不支持泛型(使泛型工作的方法都依赖于标记扩展,Silverlight不支持)
  • 大失败

    在我看来,唯一的办法就是

  • 欺骗并绑定到我的ViewModel中的字符串属性,其setter/getter执行转换,使用视图中的代码将值加载到ComboBox中
  • 为我要绑定到的每个枚举创建一个自定义的
    IValueConverter
  • 有没有更通用的替代方案,也就是说,不需要为我想要的每个枚举反复编写相同的代码?我想我可以使用一个接受枚举作为类型参数的通用类来完成解决方案#2,然后为我想要的每个枚举创建新的类,这些类只是

    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字段)
    似乎XAML的顺序也很重要,我必须在SelectedIndex之前放置ItemsSource,否则它不会调用
    <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;
            }
        }
    }