Friday, August 17, 2012

Filter enum type - Show a subset of enum values

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 )

5 comments:

  1. Hi Alex, I would like to see your example in source code for this article. Thank you for you help.

    ReplyDelete
  2. Tan Le, I am not sure what you mean, but if you want to see how to display filtered enum subset, please refer to this link : http://dotnetbeyond.blogspot.com/2012/08/wpf-propertygrid-display-partial-enum.html

    ReplyDelete
    Replies
    1. Thanks for your replying. But I mean can you give me current source code of this example.

      Delete
    2. Tan Le - The post is 1 yr old. I am afraid that I cannot find the source code... Sorry.

      Delete