Introduction
At first, I'd like to say that this control exists in two versions. First version is Windows Forms user control (namespace EeekSoft.WinForms.Controls
) and second is web control that can be used from ASP.NET applications (namespace EeekSoft.Web.Controls
). Each control is compiled to a single independent DLL file, so you can use first assembly in WinForms applications and second in web applications. Both controls have same (or very similar) functionality, so I decided to put these two controls in one article.
These controls can be used to allow users to enter value of any enumeration data type (in C#, it is enum
and in VB.NET Enum
data type). This is possible, thanks to reflection, because using reflection, the control can get all enumeration values and their names. One problem is that enumeration can be used for selecting one value from specified options or to store data as bitwise flags, and the control must be able to edit both of these types. Also, there are some other useful features that will be discussed later.
Background
This control generates a set of RadioButton
or CheckBox
(when enum
allows to choose more values) controls. You can specify this using EditorType
property, which can have one of the following values: Flags
means that user can choose more values (CheckBox
es), Options
means that user can choose only one value (RadioButton
s), and third value is Auto
. In the third case, control checks whether enumeration is marked using FlagsAttribute
attribute (this is standard attribute used with enumerations) and behaves as Flags
editor or Options
editor automatically.
Reflection
Thanks to reflection, it is possible to edit any kind of enumeration using these controls. First interesting thing that I'd like to discuss is how to get list of all values of enum
. Following code will first get System.Type
object of enumeration using typeof
operator. Then, it gets all its fields using GetFields
method. This method returns array of all fields of type, so it is simple to loop through it and find all acceptable fields.
FieldInfo[] fields=typeof(MyEnum).GetFields();
foreach(FieldInfo field in fields)
{
if (field.IsSpecialName) continue;
object valObj=field.GetValue(0));
int val=(int)valObj;
AddControl(val,field.Name);
}
Attributes
I also used attributes to control behavior of controls. I already mentioned attribute FlagsAttribute
that is used for determining enumeration type. Other used attributes are from namespace System.ComponentModel
. First attribute (BrowsableAttribute
) is used to choose which values of enum
should the user be able to select, and second (DescriptionAttribute
) allows you to add description for each value.
Following code shows how to find out if field should be hidden (it is hidden when it is marked with attribute Browsable(false)
) and get description of value. It uses method GetCustomAttributes
, of FieldInfo
which returns array with information about attributes of specified type.
object[] attrs;
attrs=field.GetCustomAttributes(typeof(BrowsableAttribute),false);
if (attrs.Length==1)
{
BrowsableAttribute brAttr=(BrowsableAttribute)attrs[0];
if (brAttr.Browsable==false) continue;
}
string description="";
attrs=field.GetCustomAttributes(typeof(DescriptionAttribute),false);
if (attrs.Length>0)
{
description=((DescriptionAttribute)attrs[0]).Description;
}
How to use these controls
Both controls work similar, but there are some little differences that will be discussed later. In all examples, I will use following two enumerations. (First is marked with FlagsAttribute
, so user can select more than one flag - control will generate CheckBox
es, and second, enum
can be used to select only one of three values, so editor will contain RadioButton
s):
[Flags]
enum MyFlagsEnum
{
false)> None=0,
false)> BothFlags=3,
[Description("First flag")] FirstFlag=1,
[Description("Second flag")] SecondFlag=2,
[Description("Third flag")] ThirdFlag=4
}
enum MyOptionsEnum
{
[Description("First option")] FirstOpt=1,
[Description("Second option")] SecondOpt=2,
[Description("Third option")] ThirdOpt=3
}
WinForms control
If you want to add this control to your form, you can use designer. (If you want to add control to your toolbox, click on 'Add/Remove items' in toolbox context menu and select assembly with control.) You can modify only properties which affect control look in designer and the rest (enumeration type) can be changed only from code. ControlSpacing
property specifies vertical offset of generated controls. LabelFormat
property allows you to set format of text labels. You can use two parameters: {0}
specifies name of value and {1}
is description stored in DescriptionAttribute
attribute. As I said before, you can override default controls behavior. If you want to use it as bitwise flags editor, set EditorType
to Flags
, and for choosing one option, use Options
. One thing that can't be done using designer is to set type of enumeration (property EnumType
as you can see in following example). Control has one event called Change
that is raised when value of enumeration changes.
private void TestForm_Load(object sender, System.EventArgs e)
{
myFlagsEditor.EnumType=typeof(MyFlagsEnum);
myFlagsEditor.EnumValue=(long)
(MyFlagsEnum.FirstFlag | MyFlagsEnum.SecondFlag);
myOptsEditor.EnumType=typeof(MyOptionsEnum);
myOptsEditor.EnumValue=(long)MyOptionsEnum.ThirdOpt;
}
ASP.NET control
ASP.NET version of control is very similar to WinForms control. After you add control to toolbox, you can put it on the web form and set its design properties using Web Forms designer. But as in WinForms version, you must set type of edited enum
manually (for example, in Page_Load
event handler).
Only one important difference between properties of WinForms and ASP.NET controls: ASP.NET version doesn't have a ControlSpacing
property (because I think it is better not to use absolute positioning in web applications for this). Instead of this, you can use ControlSeparator
property to specify HTML tags which will control space put between every two generated RadiButton
s or CheckBox
es. The default value for this property is <br />
, but if you prefer to use table layout, you can simply modify it. Also, there is a little modification in event model. Property AutoPostBack
allows you to set when page postback should occur. If you set it to true
, page will do postback (and Change
event will be called) whenever the value is changed, and if you set it to false
, control will never raise postback and Change
event will be called after page is sent back to the server for some other reason.
Following code sample shows how to add enum
editor control to web form and how to use it from codebehind (code in cs file presumes, that you set event handler for Change
event in designer):
<!---->
<%@ Page language="c#" Codebehind="EnumEditorDemo.aspx.cs"
Inherits="WebFormsDemo.EnumEditorDemo" %>
<%@ Register TagPrefix="ec" Namespace="EeekSoft.Web.Controls"
Assembly="EeekSoft.Web.EnumEditor" %>
...
<ec:enumeditor id="myFlagsEditor" LableFormat="{0} - {1}"
runat="server" ControlSeparator="<br />"></ec:enumeditor>
<asp:label id="valueLabel" runat="server"><asp:label>
...
private void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
myFlagsEditor.EnumType=typeof(MyFlagsEnum);
myFlagsEditor.EnumValue=(long)
(MyFlagsEnum.FirstFlag | MyFlagsEnum.SecondFlag);
}
}
private void myFlagsEditor_Change(object sender, EventArgs e)
{
valueLabel.Text=((MyFlagsEnum)myFlagsEditor.EnumValue).ToString();
}
Who can use it?
I think that both ASP.NET and WinForms versions of the control can be very useful if you want to allow user to modify settings of your application, and especially if you store this settings in enumerations. Typical use case may be when you load integer containing value of enumeration from database and you want to allow user to simply change its value and save it back to database. In this case, you can write a lot of code and add lot of CheckBox
and RadioButton
controls, or you can use this control and define structure of data very simply and clearly using enum
(and this solution is also very easy to maintain).