Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用组合框MVVM绑定枚举描述_C#_Wpf_Mvvm_Dependency Properties - Fatal编程技术网

C# 使用组合框MVVM绑定枚举描述

C# 使用组合框MVVM绑定枚举描述,c#,wpf,mvvm,dependency-properties,C#,Wpf,Mvvm,Dependency Properties,Hi Iam使用依赖项对象将我的combobox与enum绑定。我搜索并发现这个解决方案对于MVVM非常优雅 我的xaml是 <ComboBox SelectedItem="{Binding Color,Mode=TwoWay}" l:EnumHelper.Enum="{x:Type l:MyEnum }"></ComboBox> 我想知道,如果我必须阅读枚举描述并使用dependency object将其转换回,我如何扩展此h

Hi Iam使用依赖项对象将我的combobox与enum绑定。我搜索并发现这个解决方案对于MVVM非常优雅

我的xaml是

   <ComboBox SelectedItem="{Binding Color,Mode=TwoWay}" 
                 l:EnumHelper.Enum="{x:Type l:MyEnum }"></ComboBox>

我想知道,如果我必须阅读枚举描述并使用dependency object将其转换回,我如何扩展此helper类。

我使用与
MarkupExtension稍有不同的方法,而不是附加属性:

public sealed class EnumValues : MarkupExtension
{
    private readonly Type _enumType;

    public EnumValues(Type enumType)
    {
        _enumType = enumType;
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return Enum.GetValues(_enumType);
    }
}
我发现它更优雅,因为它更短,我可以编写
ItemsSource=“{l:EnumValues{l:MyEnum}}”

对于枚举值描述,我使用了一个转换器:

public sealed class EnumValueToDecriptionConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if(value == null)
        {
            return null;
        }
        var type = value.GetType();
        if(!type.IsEnum)
        {
            return null;
        }
        var field = type.GetField(value.ToString());
        var attr = field.GetCustomAttributes(typeof(DescriptionAttribute), true)
                        .Cast<DescriptionAttribute>()
                        .FirstOrDefault();
        if(attr != null)
        {
            return attr.Description;
        }
        else
        {
            return field.Name;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }

    #endregion
}
公共密封类EnumValueToDecriptionConverter:IValueConverter
{
#区域转换器成员
公共对象转换(对象值、类型targetType、对象参数、CultureInfo区域性)
{
如果(值==null)
{
返回null;
}
var type=value.GetType();
如果(!type.IsEnum)
{
返回null;
}
var field=type.GetField(value.ToString());
var attr=field.GetCustomAttributes(typeof(DescriptionAttribute),true)
.Cast()
.FirstOrDefault();
如果(attr!=null)
{
返回属性描述;
}
其他的
{
返回字段名称;
}
}
公共对象转换回(对象值、类型targetType、对象参数、CultureInfo区域性)
{
抛出新的NotSupportedException();
}
#端区
}
最后,您可以用XAML编写以下内容:

<ComboBox SelectedItem="{Binding Color, Mode=TwoWay}" 
          ItemsSource="{l:EnumValues {x:Type l:MyEnum}}">
    <FrameworkElement.Resources>
        <l:EnumValueToDecriptionConverter x:Key="EnumValueToDecriptionConverter" />
    </FrameworkElement.Resources>
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Mode=OneTime,
                       Converter={StaticResource EnumValueToDecriptionConverter}}" />
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>


如果您多次需要此
数据模板,可以将其定义为应用程序级别的资源。

我对
标记扩展使用稍微不同的方法,而不是附加属性:

public sealed class EnumValues : MarkupExtension
{
    private readonly Type _enumType;

    public EnumValues(Type enumType)
    {
        _enumType = enumType;
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return Enum.GetValues(_enumType);
    }
}
我发现它更优雅,因为它更短,我可以编写
ItemsSource=“{l:EnumValues{l:MyEnum}}”

对于枚举值描述,我使用了一个转换器:

public sealed class EnumValueToDecriptionConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if(value == null)
        {
            return null;
        }
        var type = value.GetType();
        if(!type.IsEnum)
        {
            return null;
        }
        var field = type.GetField(value.ToString());
        var attr = field.GetCustomAttributes(typeof(DescriptionAttribute), true)
                        .Cast<DescriptionAttribute>()
                        .FirstOrDefault();
        if(attr != null)
        {
            return attr.Description;
        }
        else
        {
            return field.Name;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }

    #endregion
}
公共密封类EnumValueToDecriptionConverter:IValueConverter
{
#区域转换器成员
公共对象转换(对象值、类型targetType、对象参数、CultureInfo区域性)
{
如果(值==null)
{
返回null;
}
var type=value.GetType();
如果(!type.IsEnum)
{
返回null;
}
var field=type.GetField(value.ToString());
var attr=field.GetCustomAttributes(typeof(DescriptionAttribute),true)
.Cast()
.FirstOrDefault();
如果(attr!=null)
{
返回属性描述;
}
其他的
{
返回字段名称;
}
}
公共对象转换回(对象值、类型targetType、对象参数、CultureInfo区域性)
{
抛出新的NotSupportedException();
}
#端区
}
最后,您可以用XAML编写以下内容:

<ComboBox SelectedItem="{Binding Color, Mode=TwoWay}" 
          ItemsSource="{l:EnumValues {x:Type l:MyEnum}}">
    <FrameworkElement.Resources>
        <l:EnumValueToDecriptionConverter x:Key="EnumValueToDecriptionConverter" />
    </FrameworkElement.Resources>
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Mode=OneTime,
                       Converter={StaticResource EnumValueToDecriptionConverter}}" />
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>


如果您多次需要此
数据模板,可以将其定义为应用程序级别的资源。

为了减少重复代码,我使用了一个自定义控件:

以下是自定义EnumComboBox控件的用法:


EnumComboBox只是从组合框继承,如下所示:(EnumComboBox.xaml)


EnumComboBox.xaml.cs:

公共部分类枚举组合框
{
公共枚举组合框()
{
初始化组件();
}
公共类型枚举类型
{
get{return(Type)GetValue(EnumTypeProperty);}
set{SetValue(EnumTypeProperty,value);}
}
公共枚举SelectedEnumValue
{
获取{return(Enum)GetValue(SelectedEnumValueProperty);}
set{SetValue(selectedUnmValueProperty,value);}
}
公共静态只读DependencyProperty EnumTypeProperty=
Register(“EnumType”、typeof(Type)、typeof(EnumComboBox)、newUIPropertyMetadata(null));
公共静态只读从属属性SelectedEnumValueProperty=
Register(“SelectedEnumValue”、typeof(Enum)、typeof(EnumComboBox)、new-UIPropertyMetadata(null));
专用只读词典_conversionDictionary=新词典();
受保护的重写无效OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
if(e.Property==EnumTypeProperty)
{
foreach(Enum.GetValues(EnumType)中的var en)
{
var descr=描述((枚举)en);
_conversionDictionary.Add(descr,(Enum)en);
}
ItemsSource=\u conversionDictionary.Keys.OrderBy(x=>x);
}
else if(e.Property==SelectedItemProperty)
{
SelectedEnumValue=_conversionDictionary[e.NewValue.ToString()];
}
else if(e.Property==selectedUnmValueProperty)
{
SetValue(SelectedItemProperty,Description((Enum)e.NewValue));
}
根据改变的财产(e);
}
公共静态字符串描述(枚举值)
{
如果(值==null)
返回null;
var enumType=value.GetType();
var field=enumType.GetField(value.ToString());
如果(字段==null)
返回null;
var attr=field.GetCustomAttributes(typeof(DescriptionAttribute),true)
.Cast()
.FirstOrDefault();
返回attr==null?value.ToString():attr.Description;
}
}
这正是我喜欢的方式,我想分享它,以防其他人想使用它。
特别是因为我花了一段时间才弄明白:)

为了减少重复代码,我使用了一个自定义控件:

以下是自定义EnumComboBox控件的用法:


EnumComboBox只是从这样的ComboBox继承:
public partial class EnumComboBox
{
    public EnumComboBox()
    {
        InitializeComponent();
    }

    public Type EnumType
    {
        get { return (Type)GetValue(EnumTypeProperty); }
        set { SetValue(EnumTypeProperty, value); }
    }

    public Enum SelectedEnumValue
    {
        get { return (Enum)GetValue(SelectedEnumValueProperty); }
        set { SetValue(SelectedEnumValueProperty, value); }
    }

    public static readonly DependencyProperty EnumTypeProperty =
        DependencyProperty.Register("EnumType", typeof(Type), typeof(EnumComboBox), new UIPropertyMetadata(null));
    public static readonly DependencyProperty SelectedEnumValueProperty =
        DependencyProperty.Register("SelectedEnumValue", typeof(Enum), typeof(EnumComboBox), new UIPropertyMetadata(null));

    private readonly Dictionary<string, Enum> _conversionDictionary = new Dictionary<string, Enum>();

    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
        if (e.Property == EnumTypeProperty)
        {
            foreach (var en in Enum.GetValues(EnumType))
            {
                var descr = Description((Enum)en);
                _conversionDictionary.Add(descr, (Enum)en);
            }
            ItemsSource = _conversionDictionary.Keys.OrderBy(x => x);
        }
        else if (e.Property == SelectedItemProperty)
        {
            SelectedEnumValue = _conversionDictionary[e.NewValue.ToString()];
        }
        else if (e.Property == SelectedEnumValueProperty)
        {
            SetValue(SelectedItemProperty, Description((Enum)e.NewValue));
        }
        base.OnPropertyChanged(e);
    }
    public static string Description(Enum value)
    {
        if (value == null)
            return null;
        var enumType = value.GetType();
        var field = enumType.GetField(value.ToString());
        if (field == null)
            return null;
        var attr = field.GetCustomAttributes(typeof(DescriptionAttribute), true)
                    .Cast<DescriptionAttribute>()
                    .FirstOrDefault();
        return attr == null ? value.ToString() : attr.Description;
    }
}