2009-10-08 6 views
11

Esta es una pregunta similar a How to bind a custom Enum description to a DataGrid, pero en mi caso tengo varias propiedades.Data bind enum properties to grid and display description

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

estoy atando un BindingList <TestResult> a un WinForms DataGridView (en realidad un DevExpress.XtraGrid.GridControl, pero una solución genérica habría más ampliamente aplicable). Quiero que aparezcan las descripciones en lugar de los nombres enum. ¿Cómo puedo lograr esto? (No hay restricciones en la clase/enum/attributes; puedo cambiarlos a voluntad.)

Respuesta

10

A TypeConverter generalmente hará el trabajo; aquí hay un código que funciona para DataGridView - simplemente agregue su código para leer las descripciones (a través de la reflexión, etc.). Acabo de usar un prefijo de cadena por ahora para mostrar que el código personalizado funciona).

Tenga en cuenta que probablemente también desee sobrescribir ConvertFrom. El convertidor se puede especificar en el tipo o el nivel de propiedad (en caso de que solo desee aplicar algunas propiedades), y también se puede aplicar en tiempo de ejecución si la enumeración no está bajo su control.

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

Thanks Marc! Combinado con nuestro EnumHelper (similar a la primera parte de la respuesta de rally25rs), esta elegante solución funciona maravillosamente, en un DataGridView. Desafortunadamente, descubrí que DevExpress.XtraGrid.GridControl ** ** no detecta el atributo TypeConverter. Suspiro. Pero tu respuesta es claramente correcta. – TrueWill

+1

... y me apuntó en la dirección correcta. Descubrí que Developer Express no planea respaldar esto, y ofrece esta solución alternativa: http://www.devexpress.com/Support/Center/p/CS2436.aspx – TrueWill

5

No estoy seguro de lo mucho que esto ayuda, pero yo uso un método de extensión en la enumeración que tiene este aspecto:

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

Se puede usar un captador de propiedad personalizada en el objeto de devolver la nombre:

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

a continuación, vincular a su rejilla a la "RequiredExpectationResultDescr" y propiedades "NonRequiredExpectationResultDescr".

que podría ser un poco más complicado, pero es la primera cosa que se me ocurrió :)

+0

+1 para una buena sugerencia, gracias; ya tenemos una clase EnumHelper como su ejemplo, y otro desarrollador sugirió las propiedades de la cadena, pero soy flojo. ;) – TrueWill

2

Sobre la base de las otras dos respuestas, he elaborado una clase que puede convertir genéricamente entre una enumeración arbitraria y una cadena usando un atributo de Descripción en cada valor enum.

Esto usa System.ComponentModel para la definición de DescriptionAttribute, y solo admite la conversión entre T y 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); 
    } 
}