A UI and Culture Friendly Replacement for Enumeration Types

30
Jun
2008

A UI and Culture Friendly Replacement for Enumeration Types

Using an enumeration to display a list of values in the user interface (UI) has obvious limitations. You'll be limited to the rules of enumeration values - no spaces, multi-words etc. You won't be able to offer localized versions of the strings used to describe each enumeration value. And you'll have to hard code and parse all possible values in order to present a list of values in a UI element.

Here's an article on five great patterns that can be used to create "look-up" or "reference" types (reference type in this case meaning a data structure that is used to represent a list of possible values that another type will depend on - like High, Medium, Low, or Fast and Slow).

Below is the code I used recently to create a type based on the descriptor pattern; a  reference type that will be used to assign a JobStatus to a Job class. What I like about this approach, is that with correct == and != operator overloads - it's a 1:1 swap with an existing enumeration type - so no code changes are required where an enumeration type may have been used initially.

The weakness of this pattern is that like enumerations - the class has to be coded - and so if the list of values changes the code will need to change too. That said, for small to medium size lists of "look-up" values (combined with a little code generation) this is a great way to offer type safe values as well as a UI and culture friendly list.

The ToString() override and the IList<JobStatius> GetValues() method make this type databinding friendly too.

public sealed class JobStatus
{
    //Private constructor - only our static properties are allowed to create instances
    private JobStatus(int value, string name)
    {
        _value = value;
        _name = String.Copy(name);
    }
    
    //Readonly Value property
    private int _value;
    public int Value { get { return _value; } }

    //Readonly Name property
    private string _name;
    public string Name { get { return _name; }}

    private static JobStatus _waiting = new JobStatus(1, "Waiting");
    public static JobStatus Waiting
    {
        get { return _waiting; }
    }

    private static JobStatus _notRun = new JobStatus(2, "Not Run");
    public static JobStatus NotRun
    {
        get { return _notRun; }
    }

    private static JobStatus _active = new JobStatus(3, "Active");
    public static JobStatus Active
    {
        get { return _active; }
    }

    private static JobStatus _completed = new JobStatus(4, "Completed");
    public static JobStatus Completed
    {
        get { return _completed; }
    }

    private static JobStatus _cancelled = new JobStatus(5, "Cancelled");
    public static JobStatus Cancelled
    {
        get { return _cancelled; }
    }

    private static JobStatus _failed = new JobStatus(6, "Failed");
    public static JobStatus Failed
    {
        get { return _failed; }
    }

    public override string ToString()
    {
        return _name;
    }
    
    public override int GetHashCode()
    {
        return _value.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;

        if (GetType() != obj.GetType())
            return false;

        JobStatus status = (JobStatus)obj;

        if (_value != status.Value)
            return false;

        return _value == status.Value;
    }     

    public static bool operator ==(JobStatus status1, JobStatus status2)
    {
        return Object.Equals(status1, status2);
    }

    public static bool operator !=(JobStatus status1, JobStatus status2)
    {
        return !Object.Equals(status1, status2);
    }

    public static IList<JobStatus> GetValues()
    {
        List<JobStatus> values = new List<JobStatus>();

        foreach (PropertyInfo pi in typeof(JobStatus).GetProperties())
        {
            if (pi.PropertyType.Name.Equals("JobStatus", StringComparison.Ordinal))
            {
                values.Add((JobStatus)pi.GetValue(null, null));
            }
        }

        return values;
    }
}
Category: