I've got an enum of types of data that might be shown in a .NET Forms control and I want to provide an interface for consumers of the control to filter some of the types (set some of the flags). A bit field seems the logical way to do this, unfortunately, the enum starts at 0 rather than 1 (0, 1, 2, 4, 8, ...) and can't be changed.
How can I expose this set of flags so that it can be easily configured programmatically or through the Visual Studio designer?
-
You would need to write a
UITypeEditorto do the work, and associate it with the property via[EditorAttribute].edit now with example - a fairly long one, I'm afraid - but most of the code can be shared between types, fortunately.
You can't use a single composite enum value because of the zero - so here I'm using a
HashSet<T>to hold the selected enums - fairly easy to re-work toList<T>if you have .NET 2.0/3.0, though.using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing.Design; using System.Text; using System.Windows.Forms; using System.Windows.Forms.Design; public class MyControl : UserControl { public MyControl() { Values = new HashSet<MyEnum>(); } [Editor(typeof(MyEnumSetEditor), typeof(UITypeEditor))] [TypeConverter(typeof(MyEnumSetConverter))] public HashSet<MyEnum> Values { get; set; } } public enum MyEnum { // numbers as per the question... A = 0, B = 1, C = 2, D = 4, E = 8 } class MyEnumSetEditor : EnumSetEditor<MyEnum> { } class MyEnumSetConverter : EnumSetConverter<MyEnum> { } // from here down is shared between types abstract class EnumSetConverter<T> : TypeConverter where T : struct { public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { return destinationType == typeof(string) || base.CanConvertTo(context, destinationType); } public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) { if(destinationType == typeof(string)) { HashSet<T> set = (HashSet<T>)value; if (set == null) return "(null)"; StringBuilder sb = new StringBuilder(); foreach (T item in Enum.GetValues(typeof(T))) { if (set.Contains(item)) { if (sb.Length > 0) sb.Append(", "); sb.Append(item); } } return sb.ToString(); } return base.ConvertTo(context, culture, value, destinationType); } } public abstract class EnumSetEditor<T> : UITypeEditor where T : struct { public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) { return UITypeEditorEditStyle.DropDown; } public override bool IsDropDownResizable { get { return true; } } public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) { IWindowsFormsEditorService svc = (IWindowsFormsEditorService) provider.GetService(typeof(IWindowsFormsEditorService)); HashSet<T> set = value as HashSet<T>; if (svc != null && set != null) { UserControl ctrl = new UserControl(); CheckedListBox clb = new CheckedListBox(); clb.Dock = DockStyle.Fill; Button btn = new Button(); btn.Dock = DockStyle.Bottom; foreach (T item in Enum.GetValues(typeof(T))) { clb.Items.Add(item, set.Contains(item)); } ctrl.Controls.Add(clb); ctrl.Controls.Add(btn); btn.Text = "OK"; btn.Click += delegate { set.Clear(); foreach (T item in clb.CheckedItems) { set.Add(item); } svc.CloseDropDown(); }; svc.DropDownControl(ctrl); } return value; } }dmo : Wow. Marc - I really appreciate you taking the time to do this.
0 comments:
Post a Comment