2010-01-13

Enums and string values: Improved version

Last week I wrote an entry about converting strings into enums by using their associated StringValueAttribute. Well, my friend Vicente Peña suggested another approach of the GetEnumStringValue method, which will save us the need to make the explicit cast. Here's the code:

1: /// <summary>
2: /// Get an enum from a string value attribute
3: /// </summary>
4: /// <see cref="http://hugonne.blogspot.com/2010/01/enums-and-string-values.html"/>
5: /// <remarks>Created by Vicente Peña</remarks>
6: public static T GetEnumStringValue<T>(this string value, bool ignoreCase)
7: {
8:     object result = null;
9:     Type type = typeof(T);
10:     string enumStringValue = null;
11:     if(!type.IsEnum)
12:         throw new ArgumentException("enumType should be a valid enum");
13: 
14:     foreach(FieldInfo fieldInfo in type.GetFields())
15:     {
16:         var attribs =
17:             fieldInfo.GetCustomAttributes(typeof(StringValueAttribute), false) 
18:             as StringValueAttribute[];
19:         //Get the StringValueAttribute for each enum member
20:         if(attribs != null)
21:             if(attribs.Length > 0)
22:                 enumStringValue = attribs[0].StringValue;
23: 
24:         if(string.Compare(enumStringValue, value, ignoreCase) == 0)
25:             result = Enum.Parse(type, fieldInfo.Name);
26:     }
27: 
28:     if(result != null)
29:     {
30:         return (T) result;
31:     }
32:     throw new ArgumentException("String not found");
33: }

To call it, we just have to do this:

1: UserState enu = "A".GetEnumStringValue<UserState>(true);

2010-01-12

Moving the focus to the next element with the Enter key

In Windows applications where users have to input big amounts of data, some people find it better to be able to move to the next control in the Form with the Enter key (as well as the Tab key). To accomplish that, you could always handle the KeyDown event on each control, and move the focus to the next control in the list. While this is effective, it'll get boring if your form has a lot of controls.

The other way around is to handle the Form's KeyDown event directly, and move to the next UIElement in the list. Something like this (the example is done with a WPF Window object, not a WinForm, but the idea is the same):

  1: private void Window_KeyDown(object sender, KeyEventArgs e)
  2: {
  3:     //Enable this code if you don't want to use the Tab key anymore
  4:     /*if (e.Key == Key.Tab)
  5:     {
  6:         e.Handled = true;
  7:         return;
  8:     }*/
  9: 
 10:     if (e.Key == Key.Enter)
 11:     {
 12:         var tRequest = new TraversalRequest(FocusNavigationDirection.Next);
 13:         var keyboardFocus = Keyboard.FocusedElement as UIElement;
 14: 
 15:         if (keyboardFocus != null)
 16:         {
 17:             keyboardFocus.MoveFocus(tRequest);
 18:         }
 19: 
 20:         e.Handled = true;
 21:     }
 22: }

As Ben Ronco – MSFT recommended it in the forumk thread I started asking this: "be careful when using a key like Enter to control navigation if the elements in your application include controls that also consume Enter keystrokes".

2010-01-06

Enums and String values

Recently, I had the need to set string values for enums, instead of using int values. Browsing the web, I came to Stefan Sedich’s blog, which had a very interesting article on creating string value attributes for enums. The article explained how to assign a custom string attribute to each enum value, and then how to get that string value from the enum by using reflection.

The article, as I said, was great, but it was missing one thing: working the other way around. I mean, it explained how to get the string value from the enum, but not how to get the enum value from the string. I needed both "ends" of the feature, With the help of a CodeProject article I found, I got to implement it succesfully.

So, to tell the whole story, here's how it basically works:

First, create a custom Attribute (a class that inherits the Attribute class)

  1: public class StringValueAttribute : Attribute
  2: {
  3:     /// <summary>
  4:     /// Holds the stringvalue for a value in an enum.
  5:     /// </summary>
  6:     public string StringValue { get; protected set; }
  7: 
  8:     /// <summary>
  9:     /// Constructor used to init a StringValue Attribute
 10:     /// </summary>
 11:     /// <param name="value"></param>
 12:     public StringValueAttribute(string value)
 13:     {
 14:         this.StringValue = value;
 15:     }
 16: }
Second, add the attribute to each one of your enum values:
  1: public enum UserState
  2: {
  3:     [StringValueAttribute("A")]
  4:     Active,
  5:     [StringValueAttribute("I")]
  6:     Inactive,
  7:     [StringValueAttribute("S")]
  8:     StandBy
  9: } 

Now, to get the associated string for a given enum value, you create an Extension Method for the Enum type:

  1: public static string GetStringValue(this Enum value)
  2: {
  3:     // Get the type
  4:     Type type = value.GetType();
  5: 
  6:     // Get fieldinfo for this type
  7:     FieldInfo fieldInfo = type.GetField(value.ToString());
  8: 
  9:     // Get the stringvalue attributes
 10:     var attribs = 
 11:         fieldInfo.GetCustomAttributes(typeof(StringValueAttribute), false) 
 12:         as StringValueAttribute[];
 13: 
 14:     // Return the first if there was a match.
 15:     return attribs.Length > 0 ? attribs[0].StringValue : null;
 16: }

To get the string value for the enum, we just needed to call the extension method:

  1: string state = UserState.Inactive.GetStringValue();

As I already said. This was all posted in Stefan Sedich’s article.

Now to go the other way around, here's what we need to do:

Just as in the first extension method was for the enum type and returned a string, our new one will have to be for the string type and return an enum. Actually, because the method will be generic to any enum type, we'll return an object, which will have to be casted by the caller to the appropriate type. This is the code:

  1: public static object GetEnumStringValue(this string value, 
  2:     Type enumType, bool ignoreCase)
  3: {
  4:     object result = null;
  5:     string enumStringValue = null;
  6:     if (!enumType.IsEnum)
  7:         throw new ArgumentException
  8:             ("enumType should be a valid enum");
  9: 
 10:     foreach (FieldInfo fieldInfo in enumType.GetFields())
 11:     {
 12:         var attribs = 
 13:             fieldInfo.GetCustomAttributes(typeof(StringValueAttribute), false) 
 14:             as StringValueAttribute[];
 15:         //Get the StringValueAttribute for each enum member
 16:         if (attribs.Length > 0)
 17:             enumStringValue = attribs[0].StringValue;
 18: 
 19:         if (string.Compare(enumStringValue, value, ignoreCase) == 0)
 20:             result = Enum.Parse(enumType, fieldInfo.Name);
 21:     }
 22: 
 23:     return result;
 24: }

To call it, we'll go with something like this:

  1: UserState enu = (UserState)"A".GetEnumStringValue(typeof(UserState), true);
There you go, hope you find it useful.

Adding methods to existing types with Extension Methods

Ever felt like one of the types you work with could have used a couple of extra methods? Maybe you’d want to add to the string type a method called ToHyperLink, which will add HTML tags to your string to make it a valid HyperLink. In other words, if your string is

http://msdn.microsoft.com

and you call the method, you'll get something like

<a href='http://msdn.microsoft.com'>http://msdn.microsoft.com</a>

We basically have two approaches here: one, create a class that inherits string, and implement the method there. This will mean that if you wanted to use the method on an object, it'll have to be declared as your new type, not string. The second approach is to use Extension Methods.  With this technique, you get the possibility to "add" methods to existing types without having to create derived classes, thus extending their functionality.

Extension method have to be implemented inside a static class, and of course have to be static themselves. They could return any type you want, and have to have at least one parameter, of the type you want to extend, preceded by the word this. Check out this example:

  1: public static class Extensions
  2: {
  3:     public static string ToHyperLink(this string url)
  4:     {
  5:         string hl = string.Format("<a href='{0}'>{0}</a>", url);
  6:         return hl;
  7:     }
  8: }

In the above code, we created an extension method for the string type called ToHyperLink, which returns another string. It's that simple. As said before, the catch here is just to add the keyword this, and to make both the method and its class static.

Now, if we wanted to use it, we jus need a using reference to whatever the classes' namespace is, and call it just like we call any of the other string methods:

  1: //Here call the extension method an a variable
  2: string a = "http://msdn.microsoft.com";
  3: a = a.ToHyperLink();
  4: //Here we call the extension method on a plain string
  5: string b = "http://hugonne.blogspot.com".ToHyperLink();

Notice line 5? You can call the extension method directly on a string value rather than a variable. This is something we couldn't have achieved with inheritance.

Extension methods can also take additional parameters. Let's say we want to create an overload for the method, which takes the text for the HyperLink. We'd add a method to our class like this:

  1: public static string ToHyperLink(this string url, string linkText)
  2: {
  3:     string hl = string.Format("<a href='{0}'>{1}</a>", url, linkText);
  4:     return hl;
  5: }

Calling the method is just as simple:

  1: string c = "http://msdn.microsoft.com";
  2: c = c.ToHyperLink("Go to MSDN");
So, extension methods are are quick way to expand the functionality of our existing types. Nevertheless, it's always good to say you should try and use them only for simple operations. If you require some sort of more complex operations, it'll be always better to use inheritance, and make your own specialized types.

One final thing: extension methods only work in the .NET Framework 3.5.