In WPF PropertyGrid 1.5, there is no way of doing enum filtering as we expect (of course). In order to facilitate enum filtering, I added an editor EnumFilterComboBoxEditor derived from ComboBoxEditor.
public class EnumFilterComboBoxEditor<T> : ComboBoxEditor where T : struct { public EnumFilterComboBoxEditor() { } protected override void ResolveValueBinding(PropertyItem propertyItem) { EnumFilter<T> enumFilter = (EnumFilter<T>)propertyItem.Value; var _binding = new Binding("Value"); _binding.Source = enumFilter; _binding.ValidatesOnExceptions = true; _binding.ValidatesOnDataErrors = true; _binding.Mode = propertyItem.IsWriteable ? BindingMode.TwoWay : BindingMode.OneWay; _binding.Converter = CreateValueConverter(); BindingOperations.SetBinding(Editor, ValueProperty, _binding); } protected override IList<object> CreateItemsSource(PropertyItem propertyItem) { return GetValues(propertyItem.Value); } private static object[] GetValues(object enumObject) { List<object> values = new List<object>(); EnumFilter<T> enumFilter = (EnumFilter<T>)enumObject; var enums = enumFilter.GetEnums(); foreach (var e in enums) { values.Add(e); } return values.ToArray(); } }
ResolveValueBinding() sets binding between source property EnumFilter<T>.Value and target Editor.ValueProperty. CreateItemsSource() sets all possible values of ComboBox items where we call GetEnums() method to get filtered enum values. And now to invoke this new type of editor, the following code added to PropertyGrid class (line 478 in propertygrid.cs).
else if (propertyItem.PropertyType.BaseType == typeof(Common.EnumFilter)) { Type tenum = propertyItem.Value.GetType().GetGenericArguments()[0]; Type filterEditor = typeof(EnumFilterComboBoxEditor<>).MakeGenericType(tenum); editor = (ITypeEditor)Activator.CreateInstance(filterEditor, true); } else if (propertyItem.PropertyType.IsEnum) // all Enums editor = new EnumComboBoxEditor();
Basically what it does is check the PropertyType and sets different editor based on the type. For enum filtering case, propertyItem.Value is EnumFilter<T> object. And calling GetGenericArguments()[0] returns the first generic argument type (that is, T). For example, for EnumFilter<MartType>, GetGenericArguments()[0] will return MartType. Next line MakeGenericType() call returns concrete type from generics by using passed argument (tenum). So filterEditor will be EnumFilterComboBoxEditor<MartType> type. Please note C# generics cannot be a type unless generic argument T is specified. Once we got the concrete type, we can create an instance from it by using Activator.CreateInstance() method as seen in the next line. I think the sample code snippet is not optimized due to lack of time. Just wanted to summarize my thought...
PropertyGrid .NET component
ReplyDelete