Introduction
An enum is a distinct type consisting of a set of named constants. A very useful feature when we are definite about all the values that a variable can have (for example, control alignment). We can use an enum and define all possible values for it. And when we use it within code, we have named constants, very clean and safe. Sometimes we need to show the value of a variable of some enum type to the user. It's very easy to do that using the ToString()
function. But sometimes, we have constants defined for our enums that do not go very well with usability testing. Consider the enum below:
public enum AlignmentEnum
{
TopLeft,
TopRight,
TopCenter,
CenterCenter,
BottomRight,
BottomLeft,
BottomCenter
}
When these constants are displayed to the user (say, on a form), they would appear as is. TopLeft.ToString()
would return "TopLeft
" and so on. Those constants look pretty straightforward to read and understand to most of us. But they are sure to find place in usability testing notes. Your tester is going to tell you that TopLeft should be displayed as "Top of Left" and that what could the user possibly make out of CenterCenter?! Now, I agree that sometimes developers do get a little emotional with their naming habits, but they have their own way of understanding them! So what is the solution?
Proposed Solution
It would be wonderful if we could somehow just map these constants with some user friendly names. Wherever we need to display an enum, the user friendly value would be displayed, and whenever we need to use the constant, the actual enum would be available. This could be a solution that can handle the usability tests and the strange naming habits of my developer brothers.
The Solution
This is a simple solution. We create a custom attribute class that has a couple of properties to describe a constant from an enum. And then we use it to decorate our enum with attributes describing each one of the constants. There goes our mapping of enum constants with user-friendly names. And to create an item source out of the list of these attributes (so that we can use it in our ListBox
or anywhere we want to display the enum constants), we use a class derived from TypeDelegator
. Here, ObjectDataProvider
helps us in XAML to create the required enumerator from the GetCustomAttributes
function of the TypeDelegator
class.
Explaining the Solution
The solution is made out of three parts. We use custom attributes to describe each one of the enum constants' user friendly names (DescriptionAttribute
class in the project).
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
sealed class DescriptionAttribute : Attribute
{
private System.String mDescription;
public System.String Description
{
get
{
return mDescription;
}
private set
{
mDescription = value;
}
}
private System.Object mEnumConstant;
public System.Object EnumConstant
{
get
{
return mEnumConstant;
}
private set
{
mEnumConstant = value;
}
}
public DescriptionAttribute(System.Object en, System.String description)
{
mEnumConstant = en;
mDescription = description;
}
}
The class has a property called EnumConstant
to be used to store the constant from the enum for which we need a user friendly name. And then we have a Description
property that has the user friendly name for the constant in question. The DescriptionAttribute
is used to attribute the enum for each one of its constants. Decorating the enum using DescriptionAttribute
would be simple.
[UserFriendlyEnums.Description(AlignmentEnum.BottomRight, "Bottom of right")]
[UserFriendlyEnums.Description(AlignmentEnum.TopCenter, "Center top")]
[UserFriendlyEnums.Description(AlignmentEnum.BottomCenter, "Center bottom")]
[UserFriendlyEnums.Description(AlignmentEnum.CenterCenter, "Center")]
[UserFriendlyEnums.Description(AlignmentEnum.BottomLeft, "Bottom of left")]
[UserFriendlyEnums.Description(AlignmentEnum.TopLeft, "Top of left")]
[UserFriendlyEnums.Description(AlignmentEnum.TopRight, "Top of right")]
public enum AlignmentEnum
{
TopLeft,
TopRight,
TopCenter,
CenterCenter,
BottomRight,
BottomLeft,
BottomCenter
}
For every enum constant, we place an attribute on top of the enum.
We use a generic class derived from 'TypeDelegator
' for its 'GetCustomAttributes
' function (the XamlableTypeDelegator
class in the project). We create a derived class because TypeDelegator
cannot be used in XAML directly.
public class XamlableTypeDelegator:System.Reflection.TypeDelegator
{
public XamlableTypeDelegator(Type delegatingType) :
base(delegatingType) { }
}
And finally, we use ObjectDataProvider
to create an instance of the aforesaid generic class to create an item source from the GetCustomAttributes
function (the resource with the name 'UserFriendlyEnumProvider
' that is actually a ObjectDataProvider
object).
<ObjectDataProvider MethodName="GetCustomAttributes"
ObjectType="{x:Type this:XamlableTypeDelegator}"
x:Key="UserFriendlyEnumProvider" >
<ObjectDataProvider.ConstructorParameters>
<x:Type TypeName="this:AlignmentEnum"/>
</ObjectDataProvider.ConstructorParameters>
<ObjectDataProvider.MethodParameters>
<sys:Boolean>false</sys:Boolean>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
This is the final step of our solution, where we finally ready with a list of DescriptionAttribute
objects, one each for all the constants of an enum. We can use it as an item source for any control exposing this property. In the demo application, we also use CollectionViewSource
to sort the list of enum constants.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.