Данные связывают свойства перечисления с сеткой и описанием отображения
Это аналогичный вопрос Как связать пользовательское описание Enum с 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, но универсальное решение будет более широко применяться). Я хочу, чтобы описания отображались, а не имена перечислений. Как я могу это сделать? (Нет ограничений на атрибуты class/enum/, я могу их по желанию изменять.)
Ответы
Ответ 1
A 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);
}
}
Ответ 2
Я не уверен, насколько это помогает, но я использую метод расширения для Enum, который выглядит следующим образом:
/// <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();
}
Вы можете использовать пользовательский атрибут свойства на своем объекте, чтобы вернуть имя:
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.
Это может быть немного сложнее, но его первое, что я придумал:)
Ответ 3
Основываясь на двух других ответах, я собрал класс, который может в общем случае конвертировать между произвольным перечислением и строкой с использованием атрибута 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);
}
}