C# 动态生成、分组和;将单选按钮绑定到枚举

C# 动态生成、分组和;将单选按钮绑定到枚举,c#,wpf,mvvm,enums,radiobuttonlist,C#,Wpf,Mvvm,Enums,Radiobuttonlist,我希望在我的ViewModel上有一个枚举,在本例中,它表示一组用户可以选择的操作。目前,我硬编码XAML中的每个单选按钮,并绑定到相应的枚举成员,使用IValueConverters获取显示值并设置所选枚举 这是可行的,但是,我希望它为枚举中的每个成员动态地生成和(如果可能的话)分组单选按钮。理想情况下,我希望根据枚举的组名,将枚举成员的单选按钮添加到它所属的组(扩展器)中 我一直在寻找实现这一目标的方法,但到目前为止,还没有找到任何适合我的、对我来说并不复杂的方法。但也许有人会在路上提供一些

我希望在我的ViewModel上有一个枚举,在本例中,它表示一组用户可以选择的操作。目前,我硬编码XAML中的每个单选按钮,并绑定到相应的枚举成员,使用IValueConverters获取显示值并设置所选枚举

这是可行的,但是,我希望它为枚举中的每个成员动态地生成和(如果可能的话)分组单选按钮。理想情况下,我希望根据枚举的组名,将枚举成员的单选按钮添加到它所属的组(扩展器)中

我一直在寻找实现这一目标的方法,但到目前为止,还没有找到任何适合我的、对我来说并不复杂的方法。但也许有人会在路上提供一些帮助,或者提供一个巧妙的解决方案

枚举:

视图:


伊瓦鲁变频器

public class EnumToBoolConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return parameter != null && parameter.Equals(value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value != null && value.Equals(true) ? parameter : DependencyProperty.UnsetValue;
    }
}

public class EnumToDisplayNameConverter : MarkupExtension, IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return ((Enum)value).GetAttributeOfType<DisplayAttribute>().Name;
    }

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

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }
}
公共类EnumToBoolConverter:IValueConverter
{
公共对象转换(对象值、类型targetType、对象参数、System.Globalization.CultureInfo区域性)
{
返回参数!=null&¶meter.Equals(值);
}
公共对象转换回(对象值、类型targetType、对象参数、System.Globalization.CultureInfo区域性)
{
返回值!=null&&value.Equals(true)?参数:dependencProperty.UnsetValue;
}
}
公共类EnumToDisplayNameConverter:MarkupExtension,IValueConverter
{
公共对象转换(对象值、类型targetType、对象参数、CultureInfo区域性)
{
返回((枚举)值);
}
公共对象转换回(对象值、类型targetType、对象参数、CultureInfo区域性)
{
抛出新的NotSupportedException();
}
公共覆盖对象ProviderValue(IServiceProvider服务提供程序)
{
归还这个;
}
}

}以下是我如何做类似事情的一个例子。基本方法是重新模板化
列表框
,并使用它动态创建单选按钮。viewmodel包含一个要显示的值列表,这些值是基于枚举值创建的(初始化时一次)。它们被绑定到
列表框

这段代码是从一个真正的应用程序中删掉的,但是你可能需要调整它,以编译/运行时不会出现错误

正如前面提到的,其中一些当然是基于我从中学到的东西

第一个-表示每个单选按钮条目的类:

    public class ListItem
    {
        public string Desc { get; set; }
        public EnumType ID { get; set; }
        public int SortOrder { get; set; }
    }
用于将数据附加到枚举的自定义属性:

[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
public class EnumMetadataAttribute : Attribute
{
    public string Description { get; set; }

    public int SortOrder { get; set; }

    public EnumMetadataAttribute(string desc)
    {
        Description = desc;
        SortOrder = 0;
    }

    public EnumMetadataAttribute(string desc, int sortOrder)
    {
        Description = desc;
        SortOrder = sortOrder;
    }
}
用于读取属性值的代码:

// based on https://stackoverflow.com/a/19621488/3195477
public static class EnumerationExtensions
{
    // This extension method is broken out so you can use a similar pattern with
    // other MetaData elements in the future. This is your base method for each.
    static T GetAttribute<T>(this Enum value) where T : Attribute
    {
        var type = value.GetType();
        var memberInfo = type.GetMember(value.ToString());
        var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false);
        return attributes.Length > 0
          ? (T)attributes[0]
          : null;
    }

    static EnumMetadataAttribute GetEnumMetadataAttribute(this Enum value)
    {
        var attr = value.GetAttribute<EnumMetadataAttribute>();
        return attr ?? new EnumMetadataAttribute(value.ToString(), 0);
    }

    public static string GetDescription(this Enum value) => value.GetEnumMetadataAttribute().Description;

    public static int GetSortOrder(this Enum value) => value.GetEnumMetadataAttribute().SortOrder;
}
自动循环所有枚举值的代码:

    void InitRadioButtonList()
    {
        foreach (EnumType enumval in Enum.GetValues(typeof(EnumName)))
        {
            RadioButtonList.Add(new ListItem
            {
                ID = enumval,
                Item = enumval.GetDescription(),
                SortOrder = enumval.GetSortOrder(),
            });
        }
    }
在viewmodel类中:

   public List<ListItem> RadioButtonList { get; } = new List<ListItem>();
   public List<ListItem> SortedRadioButtonList { get { return RadioButtonList.OrderBy(x => x.SortOrder); } }


更新-我最近读了一篇文章,其中有一些相似之处和不同之处,也值得一读。

下面是一个我如何做相似事情的例子。基本方法是重新模板化
列表框
,并使用它动态创建单选按钮。viewmodel包含一个要显示的值列表,这些值是基于枚举值创建的(初始化时一次)。它们被绑定到
列表框

这段代码是从一个真正的应用程序中删掉的,但是你可能需要调整它,以编译/运行时不会出现错误

正如前面提到的,其中一些当然是基于我从中学到的东西

第一个-表示每个单选按钮条目的类:

    public class ListItem
    {
        public string Desc { get; set; }
        public EnumType ID { get; set; }
        public int SortOrder { get; set; }
    }
用于将数据附加到枚举的自定义属性:

[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
public class EnumMetadataAttribute : Attribute
{
    public string Description { get; set; }

    public int SortOrder { get; set; }

    public EnumMetadataAttribute(string desc)
    {
        Description = desc;
        SortOrder = 0;
    }

    public EnumMetadataAttribute(string desc, int sortOrder)
    {
        Description = desc;
        SortOrder = sortOrder;
    }
}
用于读取属性值的代码:

// based on https://stackoverflow.com/a/19621488/3195477
public static class EnumerationExtensions
{
    // This extension method is broken out so you can use a similar pattern with
    // other MetaData elements in the future. This is your base method for each.
    static T GetAttribute<T>(this Enum value) where T : Attribute
    {
        var type = value.GetType();
        var memberInfo = type.GetMember(value.ToString());
        var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false);
        return attributes.Length > 0
          ? (T)attributes[0]
          : null;
    }

    static EnumMetadataAttribute GetEnumMetadataAttribute(this Enum value)
    {
        var attr = value.GetAttribute<EnumMetadataAttribute>();
        return attr ?? new EnumMetadataAttribute(value.ToString(), 0);
    }

    public static string GetDescription(this Enum value) => value.GetEnumMetadataAttribute().Description;

    public static int GetSortOrder(this Enum value) => value.GetEnumMetadataAttribute().SortOrder;
}
自动循环所有枚举值的代码:

    void InitRadioButtonList()
    {
        foreach (EnumType enumval in Enum.GetValues(typeof(EnumName)))
        {
            RadioButtonList.Add(new ListItem
            {
                ID = enumval,
                Item = enumval.GetDescription(),
                SortOrder = enumval.GetSortOrder(),
            });
        }
    }
在viewmodel类中:

   public List<ListItem> RadioButtonList { get; } = new List<ListItem>();
   public List<ListItem> SortedRadioButtonList { get { return RadioButtonList.OrderBy(x => x.SortOrder); } }

更新-我最近读了一些有相似之处和不同之处的文章,也值得一读