2009-10-08 28 views
11

Dies ist eine ähnliche Frage zu How to bind a custom Enum description to a DataGrid, aber in meinem Fall habe ich mehrere Eigenschaften.Daten Bind enum Eigenschaften zu Gitter und Anzeige Beschreibung

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; } 
} 

Ich Bindung ein Binding <Testresult> zu einem WinForms Datagridview (eigentlich ein DevExpress.XtraGrid.GridControl, aber eine generische Lösung wäre breiter anwendbar sein). Ich möchte, dass die Beschreibungen angezeigt werden und nicht die Enum-Namen. Wie kann ich das erreichen? (Es gibt keine Einschränkungen für die Klasse/enum/Attribute; ich kann sie nach Belieben ändern.)

Antwort

10

Eine TypeConverter wird normalerweise die Aufgabe erledigen; Hier ist ein Code, der für DataGridView funktioniert - fügen Sie einfach Ihren Code hinzu, um die Beschreibungen zu lesen (über Reflektion etc - Ich habe gerade ein String-Präfix verwendet, um den benutzerdefinierten Code zu zeigen).

Beachten Sie, dass Sie wahrscheinlich auch ConvertFrom überschreiben möchten. Der Konverter kann unter dem Typ oder die Eigenschaftsebene angegeben werden (falls Sie nur für einige Eigenschaften gelten sollen) und kann auch zur Laufzeit angewendet werden, wenn die Enumeration nicht unter Ihrer Kontrolle steht.

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); 
    } 
} 
+0

Danke Marc! In Kombination mit unserem EnumHelper (ähnlich dem ersten Teil der Antwort von rally25rs) funktioniert diese elegante Lösung wunderbar - in einem DataGridView. Leider habe ich festgestellt, dass DevExpress.XtraGrid.GridControl ** das TypeConverter-Attribut ** nicht erkennt. Seufzer. Aber deine Antwort ist eindeutig richtig. – TrueWill

+1

... und du hast mich in die richtige Richtung gezeigt. Ich habe festgestellt, dass Developer Express dies nicht unterstützen möchte, und bietet diese Problemumgehung: http://www.devexpress.com/Support/Center/p/CS2436.aspx – TrueWill

5

Ich bin mir nicht sicher, wie viel dies hilft aber ich benutze eine Erweiterungsmethode auf Enum, die wie folgt aussieht:

/// <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(); 
    } 

Sie eine benutzerdefinierte Eigenschaft Getter auf Ihrem Objekt verwenden, könnte die Rückkehr Name:

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(); } } 
} 

Dann binden Sie Ihre Raster auf die "RequiredExpectationResultDescr" und "NonRequiredExpectationResultDescr" Eigenschaften.

, die ein wenig zu kompliziert sein könnte, aber es ist das erste, was ich mit :)

+0

+1 für einen guten Vorschlag - danke; Wir haben bereits eine EnumHelper-Klasse wie in Ihrem Beispiel, und ein anderer Entwickler hat die String-Eigenschaften vorgeschlagen, aber ich bin faul. ;) – TrueWill

2

Basierend auf den beiden anderen Antworten kam, habe ich zusammen eine Klasse setzen, die zwischen einer beliebigen Aufzählungs allgemein umwandeln kann und Eine Zeichenfolge, die für jeden Enumerationswert ein Attribut Beschreibung verwendet.

Dies verwendet System.ComponentModel für die Definition von DescriptionAttribute und unterstützt nur die Konvertierung zwischen T und 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); 
    } 
} 
Verwandte Themen