将枚举属性绑定到网格并显示描述

11

这是一个类似于如何将自定义枚举描述绑定到DataGrid的问题,但在我的情况下,我有多个属性。

public enum ExpectationResult
{
    [Description("-")]
    NoExpectation,

    [Description("Passed")]
    Pass,

    [Description("FAILED")]
    Fail
}

public class TestResult
{
    public string TestDescription { get; set; }
    public ExpectationResult RequiredExpectationResult { get; set; }
    public ExpectationResult NonRequiredExpectationResult { get; set; }
}

我正在将一个BindingList<TestResult>绑定到WinForms DataGridView(实际上是DevExpress.XtraGrid.GridControl,但通用解决方案更加适用)。我希望显示描述而不是枚举名称。如何实现?(对于类/枚举/属性没有任何限制;我可以自由更改它们。)

3个回答

10

通常情况下,使用 TypeConverter 即可完成该任务;以下是一些针对 DataGridView 的代码示例——只需添加读取描述信息的代码(通过反射等方式——我现在只是使用字符串前缀展示自定义代码的工作原理)。

请注意,您可能还需要重写 ConvertFrom。转换器可以在类型或属性级别指定(以防只想要应用于某些属性),并且如果枚举不在您的控制之下,也可以在运行时应用。

using System.ComponentModel;
using System.Windows.Forms;
[TypeConverter(typeof(ExpectationResultConverter))]
public enum ExpectationResult
{
    [Description("-")]
    NoExpectation,

    [Description("Passed")]
    Pass,

    [Description("FAILED")]
    Fail
}

class ExpectationResultConverter : EnumConverter
{
    public ExpectationResultConverter()
        : base(
            typeof(ExpectationResult))
    { }

    public override object ConvertTo(ITypeDescriptorContext context,
        System.Globalization.CultureInfo culture, object value,
        System.Type destinationType)
    {
        if (destinationType == typeof(string))
        {
            return "abc " + value.ToString(); // your code here
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }
}

public class TestResult
{
    public string TestDescription { get; set; }
    public ExpectationResult RequiredExpectationResult { get; set; }
    public ExpectationResult NonRequiredExpectationResult { get; set; }

    static void Main()
    {
        BindingList<TestResult> list = new BindingList<TestResult>();
        DataGridView grid = new DataGridView();
        grid.DataSource = list;
        Form form = new Form();
        grid.Dock = DockStyle.Fill;
        form.Controls.Add(grid);
        Application.Run(form);
    }
}

谢谢Marc!结合我们的EnumHelper(类似于rally25rs答案的第一部分),这个优雅的解决方案在DataGridView中运行得非常好。不幸的是,我发现DevExpress.XtraGrid.GridControl无法检测到TypeConverter属性。唉。但你的答案显然是正确的。 - TrueWill
1
...而你指引了我正确的方向。我发现Developer Express没有计划支持这个,但提供了这个解决方法:http://www.devexpress.com/Support/Center/p/CS2436.aspx - TrueWill

5

我不确定这能帮到多少,但是我使用了一个枚举的扩展方法,代码如下:

    /// <summary>
    /// Returns the value of the description attribute attached to an enum value.
    /// </summary>
    /// <param name="en"></param>
    /// <returns>The text from the System.ComponentModel.DescriptionAttribute associated with the enumeration value.</returns>
    /// <remarks>
    /// To use this, create an enum and mark its members with a [Description("My Descr")] attribute.
    /// Then when you call this extension method, you will receive "My Descr".
    /// </remarks>
    /// <example><code>
    /// enum MyEnum {
    ///     [Description("Some Descriptive Text")]
    ///     EnumVal1,
    ///
    ///     [Description("Some More Descriptive Text")]
    ///     EnumVal2
    /// }
    /// 
    /// static void Main(string[] args) {
    ///     Console.PrintLine( MyEnum.EnumVal1.GetDescription() );
    /// }
    /// </code>
    /// 
    /// This will result in the output "Some Descriptive Text".
    /// </example>
    public static string GetDescription(this Enum en)
    {
        var type = en.GetType();
        var memInfo = type.GetMember(en.ToString());

        if (memInfo != null && memInfo.Length > 0)
        {
            var attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
            if (attrs != null && attrs.Length > 0)
                return ((DescriptionAttribute)attrs[0]).Description;
        }
        return en.ToString();
    }

您可以在对象上使用自定义属性 getter 来返回名称:
public class TestResult
{
    public string TestDescription { get; set; }
    public ExpectationResult RequiredExpectationResult { get; set; }
    public ExpectationResult NonRequiredExpectationResult { get; set; }

    /* *** added these new property getters *** */
    public string RequiredExpectationResultDescr { get { return this.RequiredExpectationResult.GetDescription(); } }
    public string NonRequiredExpectationResultDescr { get { return this.NonRequiredExpectationResult.GetDescription(); } }
}

然后将您的网格绑定到“RequiredExpectationResultDescr”和“NonRequiredExpectationResultDescr”属性。

这可能有点过于复杂,但这是我能想到的第一件事 :)


+1 个好建议 - 谢谢;我们已经有一个像你的示例一样的 EnumHelper 类,另一个开发人员建议使用字符串属性,但我有点懒。 ;) - TrueWill

2

根据其他两个答案,我组合了一个类,可以使用每个枚举值的Description属性通用地在任意枚举和字符串之间进行转换。

这使用System.ComponentModel定义DescriptionAttribute,并且仅支持T和String之间的转换。

public class EnumDescriptionConverter<T> : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return (sourceType == typeof(T) || sourceType == typeof(string));
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        return (destinationType == typeof(T) || destinationType == typeof(string));
    }

    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        Type typeFrom = context.Instance.GetType();

        if (typeFrom == typeof(string))
        {
            return (object)GetValue((string)context.Instance);
        }
        else if (typeFrom is T)
        {
            return (object)GetDescription((T)context.Instance);
        }
        else
        {
            throw new ArgumentException("Type converting from not supported: " + typeFrom.FullName);
        }
    }

    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
        Type typeFrom = value.GetType();

        if (typeFrom == typeof(string) && destinationType == typeof(T))
        {
            return (object)GetValue((string)value);
        }
        else if (typeFrom == typeof(T) && destinationType == typeof(string))
        {
            return (object)GetDescription((T)value);
        }
        else
        {
            throw new ArgumentException("Type converting from not supported: " + typeFrom.FullName);
        }
    }

    public string GetDescription(T en)
    {
        var type = en.GetType();
        var memInfo = type.GetMember(en.ToString());

        if (memInfo != null && memInfo.Length > 0)
        {
            var attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
            if (attrs != null && attrs.Length > 0)
                return ((DescriptionAttribute)attrs[0]).Description;
        }
        return en.ToString();
    }

    public T GetValue(string description)
    {
        foreach (T val in Enum.GetValues(typeof(T)))
        {
            string currDescription = GetDescription(val);
            if (currDescription == description)
            {
                return val;
            }
        }

        throw new ArgumentOutOfRangeException("description", "Argument description must match a Description attribute on an enum value of " + typeof(T).FullName);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接