主要原理是在枚举上添加DescriptionAttribute属性,然后通过反射将其显示出来
方法1:继承StringConverter类
public class EnumConvertor : StringConverter
{
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (!(value is string)) return base.ConvertFrom(context, culture, value);
var type = context.GetValue<Type>("PropertyType");
var field = type?.GetFields(BindingFlags.Public | BindingFlags.Static)
.FirstOrDefault(f =>
{
if (!(f.GetCustomAttribute(typeof(DescriptionAttribute)) is DescriptionAttribute description)) return false;
return description.Description.Equals(value.ToString());
});
if (type != null && field != null)
return Enum.Parse(type, field.Name);
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
// 将Enum类型转换成string进行显示
if (destinationType != typeof(string)) return base.ConvertTo(context, culture, value, destinationType);
var type = context.GetValue<Type>("PropertyType");
var field = type?.GetFields(BindingFlags.Public | BindingFlags.Static)
.FirstOrDefault(f => f.Name.Equals(value.ToString()));
if (field != null && field.GetCustomAttribute(typeof(DescriptionAttribute)) is DescriptionAttribute description)
return description.Description;
return base.ConvertTo(context, culture, value, destinationType);
}
public override StandardValuesCollection
GetStandardValues(ITypeDescriptorContext context)
{
List<string> list = new List<string>();
var type = context.GetValue<Type>("PropertyType");
foreach (var info in type.GetFields(BindingFlags.Public | BindingFlags.Static))
{
if (!(info.GetCustomAttribute(typeof(DescriptionAttribute)) is DescriptionAttribute description))
continue;
list.Add(description.Description);
}
return new StandardValuesCollection(list);
}
}
方法2:自定义界面显示
public class EnumEditor : UITypeEditor
{
private class EnumItem
{
public object Value { get; set; }
public string Name { get; set; }
}
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.DropDown;
}
public override object EditValue(ITypeDescriptorContext context,
IServiceProvider provider, object value)
{
bool cancel;
if (provider == null) return value;
if (!(provider.GetService(typeof(IWindowsFormsEditorService)) is IWindowsFormsEditorService editorService))
return value;
ListBox listBox = new ListBox
{
DisplayMember = "Name",
// 这里需要将DrawMode设置成OwnerDrawVariable才可以设置ItemHeight
DrawMode = DrawMode.OwnerDrawVariable,
//IntegralHeight = true,
Font = provider.GetValue<PropertyGrid>("OwnerGrid").Font,
SelectionMode = SelectionMode.One
};
listBox.DrawItem += (sender, args) =>
{
args.DrawBackground();
args.DrawFocusRectangle();
StringFormat strFmt = new StringFormat();
// 文本水平居中
// strFmt.Alignment = StringAlignment.Center;
// 文本垂直居中(根据需求进行设置)
strFmt.LineAlignment = StringAlignment.Center;
args.Graphics.DrawString((listBox.Items[args.Index] as EnumItem)?.Name, args.Font,
new SolidBrush(args.ForeColor), args.Bounds, strFmt);
};
listBox.MouseClick += (sender, args) =>
{
int index = ((ListBox)sender).IndexFromPoint(args.Location);
if (index < 0) return;
editorService.CloseDropDown();
};
listBox.KeyDown += (sender, args) =>
{
if (args.KeyCode != Keys.Enter) return;
editorService.CloseDropDown();
};
listBox.PreviewKeyDown += (sender, args) =>
{
if (args.KeyCode != Keys.Escape) return;
cancel = true;
editorService.CloseDropDown();
};
if (value != null)
{
Type enumType = value.GetType();
if (!enumType.IsEnum) throw new InvalidOperationException();
foreach (FieldInfo fi in enumType.GetFields(BindingFlags.Public | BindingFlags.Static))
{
EnumItem item = new EnumItem
{
Value = fi.GetValue(null)
};
object[] attributes = fi.GetCustomAttributes(typeof(DescriptionAttribute), true);
item.Name = attributes.Length > 0
? (attributes[0] as DescriptionAttribute)?.Description
: fi.Name;
int index = listBox.Items.Add(item);
if (fi.Name == value.ToString())
listBox.SetSelected(index, true);
}
}
listBox.ItemHeight += 6;
// 设置列表显示的高度
listBox.Height = listBox.ItemHeight * listBox.Items.Count + 3;
cancel = false;
editorService.DropDownControl(listBox);
return cancel || listBox.SelectedIndices.Count == 0 ? value : (listBox.SelectedItem as EnumItem)?.Value;
}
}
public class EnumConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (!(value is string)) return base.ConvertFrom(context, culture, value);
var type = context.GetValue<Type>("PropertyType");
var field = type?.GetFields(BindingFlags.Public | BindingFlags.Static)
.FirstOrDefault(f =>
{
if (!(f.GetCustomAttribute(typeof(DescriptionAttribute)) is DescriptionAttribute description)) return false;
return description.Description.Equals(value.ToString());
});
if (type != null && field != null)
return Enum.Parse(type, field.Name);
return base.ConvertFrom(context, culture, value);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return destinationType == typeof(string) || base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value,
Type destinationType)
{
// 将Enum类型转换成string进行显示
if (destinationType != typeof(string)) return base.ConvertTo(context, culture, value, destinationType);
var type = context.GetValue<Type>("PropertyType");
var field = type?.GetFields(BindingFlags.Public | BindingFlags.Static)
.FirstOrDefault(f => f.Name.Equals(value.ToString()));
if (field != null && field.GetCustomAttribute(typeof(DescriptionAttribute)) is DescriptionAttribute description)
return description.Description;
return base.ConvertTo(context, culture, value, destinationType);
}
}
使用
[Editor(typeof(EnumEditor), typeof(UITypeEditor)),
TypeConverter(typeof(Forms.Utility.EnumConverter))]
public enum Alignment
{
[Description("无")]
None,
[Description("居左")]
Left,
[Description("居中")]
Center,
[Description("居右")]
Right
}