将ComboBoxes绑定到枚举...在Silverlight中!

Dom*_*nic 38 data-binding silverlight enums xaml

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

  1. 您不能使用接受类型参数的泛型EnumDisplayer样式IValueConverter,因为Silverlight不支持x:Type.
  2. 您不能ObjectDataProvider像在此方法中那样使用,因为它在Silverlight中不存在.
  3. 您不能像#2链接中的注释那样使用自定义标记扩展,因为Silverlight中不存在标记扩展.
  4. 您不能使用泛型而不是Type对象的属性来执行#1版本,因为XAML中不支持泛型(并且使它们工作的黑客都依赖于标记扩展,Silverlight不支持).

大规模的失败!

在我看来,做这项工作的唯一方法是

  1. 欺骗并绑定到我的ViewModel中的字符串属性,其setter/getter执行转换,使用View中的代码隐藏将值加载到ComboBox中.
  2. IValueConverter为我想绑定的每个枚举制作一个自定义.

是否有更通用的替代方案,即不要为我想要的每个枚举反复编写相同的代码?我想我可以使用接受枚举作为类型参数的泛型类来做解决方案#2,然后为我想要的每个枚举创建新类

class MyEnumConverter : GenericEnumConverter<MyEnum> {}
Run Code Online (Sandbox Code Playgroud)

伙计们,你有什么想法?

Dom*_*nic 34

唉,我说得太快了!有一个非常好的解决方案,至少在Silverlight 3中.(它可能只有3个,因为这个帖子表明在Silverlight 3中修复了与这个东西相关的bug.)

基本上,您需要为该ItemsSource属性使用单个转换器,但它可以完全通用而不使用任何禁止的方法,只要您传递其类型为的属性的名称即可MyEnum.并且数据绑定SelectedItem完全没有痛苦; 不需要转换器!好吧,至少只要你不想为每个枚举值设置自定义字符串,例如DescriptionAttribute,嗯...可能需要另一个转换器用于那个; 希望我能把它变得通用.

更新:我做了一个转换器,它的工作原理!SelectedIndex可悲的是,我现在必须绑定,但没关系.使用这些家伙:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Data;

namespace DomenicDenicola.Wpf
{
    public class EnumToIntConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            // 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, System.Globalization.CultureInfo culture)
        {
            return Enum.Parse(targetType, value.ToString(), true);
        }
    }
    public class EnumToIEnumerableConverter : IValueConverter
    {
        private Dictionary<Type, List<object>> cache = new Dictionary<Type, List<object>>();

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var type = value.GetType();
            if (!this.cache.ContainsKey(type))
            {
                var fields = type.GetFields().Where(field => field.IsLiteral);
                var values = new List<object>();
                foreach (var field in fields)
                {
                    DescriptionAttribute[] a = (DescriptionAttribute[])field.GetCustomAttributes(typeof(DescriptionAttribute), false);
                    if (a != null && a.Length > 0)
                    {
                        values.Add(a[0].Description);
                    }
                    else
                    {
                        values.Add(field.GetValue(value));
                    }
                }
                this.cache[type] = values;
            }

            return this.cache[type];
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

有了这种绑定XAML:

<ComboBox x:Name="MonsterGroupRole"
          ItemsSource="{Binding MonsterGroupRole,
                                Mode=OneTime,
                                Converter={StaticResource EnumToIEnumerableConverter}}"
          SelectedIndex="{Binding MonsterGroupRole,
                                  Mode=TwoWay,
                                  Converter={StaticResource EnumToIntConverter}}" />
Run Code Online (Sandbox Code Playgroud)

这种资源声明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>
Run Code Online (Sandbox Code Playgroud)

任何评论将不胜感激,因为我有点像XAML/Silverlight/WPF /等.新手.例如,是否EnumToIntConverter.ConvertBack会慢,所以我应该考虑使用缓存?

  • 如果枚举的值不是从0开始按顺序编号,则此解决方案将失败.它取决于组合框中枚举值和索引之间的一对一对应关系.否则一个很好的解决方 (3认同)