I happen to run into the case where I have to display a subset of enum type values instead of displaying the all elements - which is common case - of the enum type. .NET enum is a predefined type, should be defined at compile time and cannot be dynamically built at run time.
To illustrate the problem domain, let's say we have a enum called MartType as follows.
public enum MartType{
Safeway,
QFC,
Alberson,
HMart
}
If we display a enum type property in PropertyGrid (actually I used WPF property grid which is included in
WPF extended toolkit), it will show a combox editor containing all enum values.
Now, what if we want to display a subset of enum values based on Area? For example, in case of another city (Bellevue), we only want to show 3 grocery stores.
In order to do this, one should restrict ItemsSource data for the ComboBox. And in order to accomplish this in WPF PropertyGrid control, one have to add a special editor to handle this special case (will write about this later).
For the example above, let's say we expose 2 properties like this.
public string Area { get; set; }
public EnumFilter<MartType> AreaMartType { get; set; }
AreaMartType public property is not simply MartType enum, but a EnumFilter of MartType. This AreaMartType is set by the following helper private method, which returns filtered enum based on areaNo.
private EnumFilter<MartType> FilterMarts(int areaNo, MartType selectedMart)
{
List subset = new List();
switch (areaNo)
{
case 1:
subset.Add(MartType.QFC);
subset.Add(MartType.Alberson);
subset.Add(MartType.HMart);
break;
case 2:
subset.Add(MartType.QFC);
subset.Add(MartType.Alberson);
subset.Add(MartType.Safeway);
break;
case 3:
subset.Add(MartType.Alberson);
subset.Add(MartType.Safeway);
subset.Add(MartType.HMart);
break;
default:
subset.Add(MartType.QFC);
subset.Add(MartType.Alberson);
subset.Add(MartType.Safeway);
subset.Add(MartType.HMart);
break;
}
EnumFilter<MartType> enumFilter = new EnumFilter<MartType>(subset);
enumFilter.Value = selectedMart;
return enumFilter;
}
So EnumFilter of T class takes enum value list which is a subset of enum values. And GetEnums() method actually do the filtering work based on the given subset. By IEnumerable and yield only filtered one, it can dynamically retrieve a subset of enum items.
public class EnumFilter
{
}
public class EnumFilter<T> : EnumFilter, INotifyPropertyChanged
where T : struct
{
private List _elements;
private T _value;
public EnumFilter()
{
_elements = new List<T>();
}
public EnumFilter(List<T> elements)
{
_elements = elements;
}
public IEnumerable<T> GetEnums()
{
foreach (var field in typeof(T).GetFields(
BindingFlags.GetField | BindingFlags.Public | BindingFlags.Static))
{
T enumVal = (T)field.GetValue(null);
if (_elements.Contains(enumVal))
{
yield return enumVal;
}
}
}
public T Value
{
get { return _value; }
set
{
_value = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Value"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
How we display the subset of enums in WPF PropertyGrid is little different topic but related. Will write more. (Please see :
http://dotnetbeyond.blogspot.com/2012/08/wpf-propertygrid-display-partial-enum.html )