Main contents

Have I mentioned lately how much I like data binding, lately? I use it everywhere I can: it makes writing UI code much easier. Anyway, working on a project at work I ran into the following problem:

Consider this code:

this.checkBox1.DataBindings.Add("Checked", this.myBindingSource, "MyBooleanProperty",
                                 true, DataSourceUpdateMode.OnPropertyChanged);

This declares a data binding on checkBox1, a CheckBox control. It uses the giant overload taking arguments that, respectively, declare the name of the property on the Control to bind to, the source of the data property, the data property, a boolean for formatting, and a DataSourceUpdateMode enum value.

The DataSourceUpdateMode.OnPropertyChanged value means that as soon as the control’s Checked property changes, then change the MyBooleanProperty on the data source. OnPropertyChanged is not the default; the default is OnValidation which typically happens when the control loses focus. I’m a fan of PropertyChanged because there are problems with OnValidation when focus doesn’t change.

Anyway, if you bind to the Checked property on CheckBox, and select DataSourceUpdateMode.OnPropertyChanged, then it updates on validation.

BZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZT! Wrong! Bug!

Fortunately, there is a workaround. If you use the useless, and practically redundant, CheckState property on CheckBox, instead of Checked, then you get OnPropertyChanged updating. Important: Make sure ‘true’ is passed for the formattingEnabled parameter, otherwise the value expected by the control will be of type CheckState, an enum.

The following code works:

this.checkBox1.DataBindings.Add("CheckState", this.myBindingSource, "MyBooleanProperty",
                                true, DataSourceUpdateMode.OnPropertyChanged);

Your welcome.

Posted in .NET | 1 Comment »

The .NET framework is huge, but not so huge that it does everything for everyone; there are things that they in Redmond miss or don’t do for whatever reason but is still generally applicable to many developers. So, dear reader, I present to you a series of posts on stuff I find missing in .NET, typically where even the Google fails to find the answer. It could be a useful class, a technique, a good practice or documentation that should be in the framework but isn’t or isn’t widely publicized. Click here for a complete list of Missing .NET entries.


I’m sure, Dear Reader, if you wait long enough, I’ll do all the exercises I leave to you in my posts. I wrote last time about displaying enums in WPF using databinding. I left it as an exercise to do this in Windows Forms and ASP.NET. Well, it turns out that I needed a Windows Forms version for more than just a programming exercise. So I figured I’d share something like it with all 5 of you regular readers.

In case you don’t want to click through to the WPF article, let me recap it here for you since we’ll be using some of the code from that article. I’m ambivalent towards enums; I often think they are less useful in many situations in which they are used than a custom class. I do, however, have little choice when it comes to using other libraries or .NET Framework code which may use them. One of the troublesome areas of enums is showing them in UI without going insane writing the same code over and over again with only the slight difference of the enum type to distinguish each version.  Last time I used the first-rate data-binding in WPF to show enums in a WPF ComboBox. Then I handled the case where you don’t own the enum. I also dealt with the issues of internationalization and human readable text instead of the names of each enum value. In this article, I’ll use the somewhat less first-rate data-binding in Windows Forms to do the same thing.

The first thing we need is a way to mark our enum with the text we want in place of the value name. The perfect way to do that, as I said last time, is to use attributes. The class I presented last time is independent of UI frameworks, so I’ll use it again here. It’s reproduced below:

using System;

namespace MissingNet.ComponentModel
{
   [AttributeUsage(AttributeTargets.Field)]
   public sealed class DisplayStringAttribute : Attribute
   {
      private readonly string value;
      public string Value
      {
         get { return value; }
      }

      public string ResourceKey { get; set; }

      public DisplayStringAttribute(string value)
      {
         this.value = value;
      }

      public DisplayStringAttribute()
      {
      }
   }
}

We can apply this to the values of our custom enum, like so:

 

public enum MyEnum
{
   [DisplayString("My Value")]
    Value,
   [DisplayString("This means On")]
    On,
   [DisplayString("Off means not On")]
    Off,
   [DisplayString("The great unknown")]
    Unknown,
   [DisplayString("I ain't got none")]
    None
}

Doesn’t look as pretty as an unadorned enum, but commercial quality code often looks less attractive than you’re typical code snippet on MSDN. If we want to internationalize our app, we can have different display strings for different languages by setting the ResourceKey property instead of the value constructor:

 

public enum MyEnum
{
   [DisplayString(ResourceKey="MyEnum_Value")] Value,
   [DisplayString(ResourceKey="MyEnum_On")] On,
   [DisplayString(ResourceKey="MyEnum_Off")] Off,
   [DisplayString(ResourceKey="MyEnum_Unknown")] Unknown,
   [DisplayString(ResourceKey="MyEnum_None")] None
}

Don’t forget to add the strings to your resx file for each language!

Now that we’ve reviewed how to associate the display strings with the enum values, we need a way to get that data into the UI. For that I’ll be using one of the unsung heroes of the .NET 2.0 WinForms improvements: BindingSource.

Earlier I called the data-binding in WinForms less than first-rate. It’s only in comparison to WPF, which isn’t really fair: WPF was designed from the ground up with data-binding as a feature. By contrast, Windows Forms is an elegant OO wrapper around the flat Win32 API, an API that is ancient in computer years. It’s so old they didn’t even have data when it was designed. So there is nothing as elegant as, say, DataContext in Windows Forms, but it’s still world’s better than the alternative of doing it all yourself.

If Win32 were a Star Wars character

If Win32 were a Star Wars character: really powerful, but really, really old

They faked it pretty good in .NET 1.1 for simple databinding (simple in the Windows Forms data binding sense of just hooking up to a property); complex databinding (binding to a list or collection or DataSet) was a bit more onerous if you modified the collection independent of the Form that was displaying it. In .NET 2.0, they improved things tremendously by following the old adage: You can at least partially solve any problem in computer science with one more level of indirection. [The full quote, attributed to David Wheeler is, "Any problem in computer science can be solved with another layer of indirection. But that usually will create another problem."]

And that level of indirection takes the form of the BindingSource. To describe the BindingSource, let me quote directly from the excellent book on the subject of Windows Forms databinding, Data Binding with Windows Forms 2.0, by Brian Noyes:

The BindingSource component solves a number of tricky problems that surfaced with the approach of directly binding data sources to controls in .NET 1.X. It provides a layer of indirection between a data source and bound controls that makes a number of things easier. Additionally, it surfaces important control points and access to the underlying data source in a way that saves you from having to delve into the data-binding mechanisms of a form the way you had to in the past. A binding source also gives you a single API to program against from the form’s perspective, and lets a lot of your form code remain decoupled from the specific data source type. This prevents you from having to adapt your programmatic coding patterns to each different type of data that your application works with… [p111-112]

Sounds perfect for our needs, doesn’t it? Displaying enums, from a Windows Forms data-binding perspective, is actually fairly easy: it’s a read-only data source with read-only items, so there is no need to deal with adding, removing or editing. In fact the only tough part is filling the “list” with the entries. We’ve already done something similar with in WPF.

Here’s the EnumBindingSource class:

public class EnumBindingSource : BindingSource
{
  private readonly object dataSource;
  private readonly PropertyInfo property;

  public EnumBindingSource(object dataSource, string propertyName)
  {
     this.dataSource = dataSource;
     this.property = dataSource.GetType().GetProperty(propertyName);
     Type enumType = property.PropertyType;
     FieldInfo[] fields = enumType.GetFields(BindingFlags.Public | BindingFlags.Static);
     List<NameEnumPair> source = new List<NameEnumPair>(fields.Length);
     foreach (FieldInfo f in fields)
     {
        DisplayStringAttribute[] a = (DisplayStringAttribute[])f.GetCustomAttributes(typeof(DisplayStringAttribute), false);
        string displayString = GetDisplayStringValue(a, enumType);
        object enumValue = f.GetValue(null);
        NameEnumPair pair = new NameEnumPair(displayString, enumValue);
        source.Add(pair);
     }
     int index = source.FindIndex(value => value.Value.Equals(property.GetValue(dataSource, null)));
     this.DataSource = source;
     this.Position = index;
  }

  public override bool AllowEdit
  {
     get { return false; }
  }

  public override bool AllowNew
  {
     get { return false; }
     set { throw new NotSupportedException();}
  }

  public override bool AllowRemove
  {
     get { return false; }
  }

  protected override void OnCurrentChanged(EventArgs e)
  {
     base.OnCurrentChanged(e);
     //set the value
     NameEnumPair value = (NameEnumPair)this.Current;
     property.SetValue(dataSource, value.Value, null);
  }

  private static string GetDisplayStringValue(DisplayStringAttribute[] a, Type type)
  {
     if (a == null || a.Length == 0) return null;
     DisplayStringAttribute dsa = a[0];
     if (!string.IsNullOrEmpty(dsa.ResourceKey))
     {
        ResourceManager rm = new ResourceManager(type);
        return rm.GetString(dsa.ResourceKey);
     }
     return dsa.Value;
  }

  private class NameEnumPair
  {
     private readonly string displayName;
     private readonly object value;

     public NameEnumPair(string displayName, object value)
     {
        this.displayName = displayName;
        this.value = value;
     }

     public string DisplayName
     {
        [DebuggerStepThrough]
        get { return displayName; }
     }

     public object Value
     {
        [DebuggerStepThrough]
        get { return value; }
     }

     public override string ToString()
     {
        return DisplayName;
     }
  }
}

All the work happens in the constructor: we use reflection to get the type of the property passed in, get the enum values in the type, read the DisplayStringAttribute values, add them to a list, set the DataSource property, and we’re done. I’ve overridden the AllowXxx properties to make this an immutable BindingSource; there are more properties to override to lock this down as a framework type, but this is a good start. If I were really hardcore, I’d implement all the interfaces that BindingSource does myself, but I don’t see the value.

So, this works for enums that you own, but like I said in the WPF article, that is really rare. What you need is a way to declare the strings for enums that you don’t own. Again, using the WPF implmentation as a reference, we merely need to create a class that will contain the data and set it appropriately. But here, we don’t have the requirement to support XAML, so we have a bit more freedom. Since this is pretty much an immutable type, setting it in the constructor is the way to go. I just need an overloaded constructor. We also need a type to hold the data we want to set. We already have that type with the nested class NameEnumPair, we just need to make it public, and probably move it to the outer scope, as most .NET types are wont to do.

Here’re the new constructors:

public EnumBindingSource(object dataSource, string propertyName)
   : this(dataSource, propertyName, null)
{
}

public EnumBindingSource(object dataSource, string propertyName, IEnumerable<NameEnumPair> overriddenDisplayValues)
{
   this.dataSource = dataSource;
   this.property = dataSource.GetType().GetProperty(propertyName);
   List<NameEnumPair> source;
   if (overriddenDisplayValues == null)
   {
      Type enumType = property.PropertyType;
      FieldInfo[] fields = enumType.GetFields(BindingFlags.Public | BindingFlags.Static);
      source = new List<NameEnumPair>(fields.Length);
      foreach (FieldInfo f in fields)
      {
         DisplayStringAttribute[] a = (DisplayStringAttribute[])f.GetCustomAttributes(typeof(DisplayStringAttribute), false);
         string displayString = GetDisplayStringValue(a, enumType);
         object enumValue = f.GetValue(null);
         NameEnumPair pair = new NameEnumPair(displayString, enumValue);
         source.Add(pair);
      }
   }
   else
   {
      source = new List<NameEnumPair>(overriddenDisplayValues);
   }
   int index = source.FindIndex(value => value.Value.Equals(property.GetValue(dataSource, null)));
   this.DataSource = source;
   this.Position = index;
}

Now we have a way to display enums in ComboBoxes in Windows Forms. Client code looks like the following:

public class MyCustomClass
{
  public MyEnum MyEnumProperty { get; set; }

  public MyCustomClass()
  {
     MyEnumProperty = MyEnum.On;
  }
}

public partial class Form1 : Form
{
  public Form1()
  {
     InitializeComponent();
     MyCustomClass myCustomObject = new MyCustomClass();
     this.comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
     this.comboBox1.DataSource = new EnumBindingSource(myCustomObject, "MyEnumProperty");
  }
}

Posted in .NET, Missing .NET | 1 Comment »

Keep it DRAFT-y

10 September 2008

The other day I was grabbing screenshots from an app I’m working on. I noticed a huge visual problem with a a list in the product: in a one-column ListView in Details view, each item’s text was truncated, as though the column’s width was just left to the default of 20 pixels (this is in .NET CF, but the problem below applies to the full framework WinForms as well). This is code I inherited, mind you! I certainly wouldn’t have coded it this way (No sir, nah-uh), but I found the offending code that that was trying to set the column width to the largest item; something like this:

private void ArrangeColumnWidth()
{
    //this is called after all the items have been added
    using (Graphics g = this.listView.CreateGraphics())
    {
        int maxWidth = 0;
        foreach (object item in this.listView.Items)
        {
            SizeF s = g.MeasureString(item.ToString());
            if (s.Width > maxWidth)
                maxWidth = s.Width;
        }
        this.listView.Columns[0].Width = maxWidth;
    }
}

Pretty standard find-the-max code, right? Except it wasn’t working. Since I knew there would always be one column, and we’d never change out of Details view, I, without thinking too hard about it, changed the above code to the following:

private void ArrangeColumnWidth()
{
    this.listView.Columns[0].Width = this.listView.Width;
}

“There! That should do it,” I thought — in the few seconds that it took me to write it. Of course, you’ve just read that, and thought, “What a fool! Anyone can see that if there are enough items in the ListView to cause scrolling vertically, then the column width will be too big, so you’ll get a horizontal scroll bar also. Duh! Everyone knows that. What was he thinking?”

And you’d be right.

But sometimes, when I’m in the flow, I have really fast edit, compile, run cycles. The first run after the above edit showed me the problem that you astute readers already found.

At this point, in my younger days, I’d bash away at determining the width of a standard scroll bar and hardcoding that number in my arithmetic. But I’ve learned the following refrain from using .NET since it came out: It’s in the Framework, Dummy!

So, I did a Google search, found a forum post, read it, couldn’t believe the solution was so simple, then went to the MSDN docs to confirm that it was true. It was! If you set the ColumnHeader.Width value to -1, it will size to the largest item. If you set the ColumnHeader.Width value to -2, it will size the header to the header text. It’s all right there on MSDN!

I didn’t know this little tidbit. So, I re-wrote the code. I got rid of the ArrangeColumnWidth() method altogether and now when I create the column, I set it’s width to -1. Problem solved!

Two things occurred to me when I read about those helpful values.

The first is that that is some old-ass .NET code. Microsoft doesn’t write .NET code like that anymore. Instead, I think it would be something like the following:

public enum ColumnWidthStyle
{
    Normal,
    SizeToMaximumItem,
    SizeToColumnHeader
}

ColumnHeader c = new ColumnHeader();
c.WidthStyle = ColumnWidthStyle.SizeToMaximumItem;

That code is more verbose, sure; but it’s way more discoverable, especially with IntelliSense. It’s also more readable; imagine coming back to this code a few months later: it would still make sense. The way we’re stuck with is essentially a magic number, a vestigial bump from the dark ol’ days of Win32 programming. I have no doubt that the ColumnHeader class is managed spackle over the Win32 equivalent, so we get those negative width numbers for free.

Even with the awkwardness of the API as it is, I’m still going to use it. That’s one method I don’t have to write. The whole point of using the .NET framework is that it does a lot for you. And yet…

I still see commercial code shipping with reams and reams of classes and methods that duplicate functionality in the Framework. Why!?!

We’ve all heard the principle of DRY (Don’t Repeat Yourself). I’ve got my own corollary, the DRAFT principle: Don’t Repeat A Framework Type. .NET, J2EE, Rails, Django, CPAN, whatever language and framework you prefer: assume they solve all your problems, learn them, use them, abuse them. And only if they are truly lacking should you write your own.

Posted in .NET, Rants, Software | 1 Comment »

How to Save XAML as an Image

2 September 2008

Here’s a quick note to self that you may enjoy. I suck at art. Didn’t use to always, but it requires too much brain power. But I’m not bad at getting WPF to draw what I want. I had a logo in mind for this site and used WPF to generate it after unsuccessfully getting Paint.NET to do the same.

I recently needed to use this code again, but forgot how I solved it. So, rather than hunt it down on Google again, I came home and loaded up ye olde Windows Live Writer to write this post.

To save the XAML you want as an image, put the elements you want to save into a canvas element called canvas. Then run the following code.

private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
   Rect rect = new Rect(canvas.RenderSize);
   RenderTargetBitmap rtb = new RenderTargetBitmap((int)rect.Right,
     (int)rect.Bottom, 96d, 96d, System.Windows.Media.PixelFormats.Default);
   rtb.Render(canvas);
   //endcode as PNG
   BitmapEncoder pngEncoder = new PngBitmapEncoder();
   pngEncoder.Frames.Add(BitmapFrame.Create(rtb));

   //save to memory stream
   System.IO.MemoryStream ms = new System.IO.MemoryStream();

   pngEncoder.Save(ms);
   ms.Close();
   System.IO.File.WriteAllBytes("logo.png", ms.ToArray());
   Console.WriteLine("Done");
}

I hooked up a key binding to a command to execute this code, but you could use a button click too. It’ll save the elements in canvas to a file in the same folder as the executable, called logo.png, but you can change that if you want. You can also you a different encoder if you like. They’re in System.Windows.Media.Imaging.

Enjoy!

Posted in .NET, Note to self... | No Comments »

The .NET framework is huge, but not so huge that it does everything for everyone; there are things that they in Redmond miss or don’t do for whatever reason but is still generally applicable to many developers. So, dear reader, I present to you a series of posts on stuff I find missing in .NET, typically where even the Google fails to find the answer. It could be a useful class, a technique, a good practice or documentation that should be in the framework but isn’t or isn’t widely publicized. Click here for a complete list of Missing .NET entries.


I’m ambivalent towards enums. They are a succinct way of providing a list of choices that don’t change that much. But, I think they are overused, often in situations that don’t lend themselves well to enums. For example, the HttpStatusCode enum in System.Net. It should probably explicitly be a list of constant integers, because that’s the way the status code is thought of to HTTP programmers, well, at least one. Consider the two code snippets below. Which one is more readable?

void ProcessResponse(WebResponse r)
{
    if (r.StatusCode >= HttpStatusCode.BadRequest)
    {
        // handle response
    }
}

void ProcessResponse(WebResponse r)
{
    if (r.StatusCode >= 400)
    {
    // handle request
    }
}

Yeah, yeah: you’re not supposed to use magic numbers, but it’s not like HTTPbis is going to redo all the status codes. It’s a safe bet that the status code with the value 400 will always mean “Bad Request”.

Anyway, Enums are here to stay and we have to deal with them in various ways; displaying them to the user is one way they have to be dealt with. I’ll give a treatment of how to display an enum in WPF in this post. You’ll see that displaying them in all situations is non-trivial.

So, let’s say you want to display a list of the values for your custom enum in a ComboBox in WPF; how do you do it? Well,  you could mess around yourself and test your WPF databinding knowledge, but no one has any patience for that nowadays. Let’s Google it! The goal of most WPF code is to do it all in XAML. So a possible solution to the problem is the following XAML snippet (copied from this post from the WPF SDK blog):

<Window
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:sys="clr-namespace:System;assembly=mscorlib"
  SizeToContent="WidthAndHeight"
  Title="Show Enums in a ListBox using Binding">
  <Window.Resources>
    <ObjectDataProvider MethodName="GetValues"
                        ObjectType="{x:Type sys:Enum}"
                        x:Key="AlignmentValues">
      <ObjectDataProvider.MethodParameters>
        <x:Type TypeName="HorizontalAlignment" />
      </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
  </Window.Resources>
  <Border Margin="10" BorderBrush="Aqua"
          BorderThickness="3" Padding="8">
    <StackPanel Width="300">
      <TextBlock>Choose the HorizontalAlignment
                 value of the Button:</TextBlock>
      <ListBox Name="myComboBox" SelectedIndex="0" Margin="8"
               ItemsSource="{Binding Source={StaticResource
                                             AlignmentValues}}"/>
      <Button Content="Click Me!"
              HorizontalAlignment="{Binding ElementName=myComboBox,
                                            Path=SelectedItem}"/>
    </StackPanel>
  </Border>
</Window>

The real magic happens in the bolded text above, the ObjectDataProvider. It calls the GetValues() method on the Enum type. The MethodParameters element contains the actual enum type to display. This is the common sample that you’ll see throughout the web. A couple problems no one seems to address with this solution, though.

The first is the what actually gets shown to the user. For simple one-word values, like the HorizontalAlignment enum used in the XAML sample above (Center, Justify, Left, Right), it’s not a problem — if you’re only coding for the English language. But what about the HttpStatusCode enum? It’ll show up with the Pascal casing BadRequest or RequestedRangeNotSatisfiable rather than “Bad Request” or “Requested Range Not Satisfiable”. That’s acceptable if your audience is a bunch of nerdy programmers (”I actually prefer no spaces, it makes 2.4321% more efficient so I can devote more time to WoW!” Nerd.), but if you’re doing this for real people, you’re going to want a nice grammatically- correct string to show up. You might want even more detail in the string: “Bad Request (400)”, say.

Second, this solution ignores localization. If you just show the name of the enum value, you get whatever language the programmer speaks. That’s fine if you only plan on shipping your product to your country, but what if you are big in Japan? You’re going to want to translate that bad boy to Japanese!

Japan's calling. Are you going to answer?

Japan’s calling. Are you going to answer?

Let’s solve that problem.

Let’s first assume that we own the enum type. We have a web product and a WPF product; we use our custom enum type in both products. We want to display the same thing for the enum values in both places. If that’s the case, we want the display strings to move around with the enum. How are we going to do that? Well, we have extra data that we want to move around with a type, perfect for … Attributes!

The simplest attribute class that will work takes a string that will be displayed in place of the enum value. But we don’t want the simplest class that will work. We want one that will also support localization. Still pretty simple and it looks like this:

[AttributeUsage(AttributeTargets.Field)]
public sealed class DisplayStringAttribute : Attribute
{
   private readonly string value;
   public string Value
   {
      get { return value; }
   }

   public string ResourceKey { get; set; }

   public DisplayStringAttribute(string v)
   {
      this.value = v;
   }

   public DisplayStringAttribute()
   {
   }
}

We can apply this to the values of our custom enum, like so:

public enum MyEnum
{
   [DisplayString("My Value")]
    Value,
   [DisplayString("This means On")]
    On,
   [DisplayString("Off means not On")]
    Off,
   [DisplayString("The great unknown")]
    Unknown,
   [DisplayString("I ain't got none")]
    None
}

Doesn’t look as pretty as an unadorned enum, but commercial quality code often looks less attractive than you’re typical code snippet on MSDN. If we want to internationalize our app, we can have different display strings for different languages by setting the ResourceKey property instead of the value constructor:

public enum MyEnum
{
   [DisplayString(ResourceKey="MyEnum_Value")] Value,
   [DisplayString(ResourceKey="MyEnum_On")] On,
   [DisplayString(ResourceKey="MyEnum_Off")] Off,
   [DisplayString(ResourceKey="MyEnum_Unknown")] Unknown,
   [DisplayString(ResourceKey="MyEnum_None")] None
}
 
Don’t forget to add the strings to your resx file for each language!
 
So we have our strings established, now we need a class that will read that data, and convert it to something that can be displayed. I’ll solve that problem for WPF specifically, but there is no reason you can’t do it for Winforms or the Web also, dear reader. It’s a good lesson in learning how to support UI frameworks and reflection
 
If you’re designing for WPF, a huge consideration is the ability to express your code in XAML. With my solution below, you’ll be able to declare these enum displayers in XAML; but as you’ll see, it makes the code a little less elegant.
 
Here are the requirements that my EnumDisplayer class must fulfill:
  • read the DisplayStringAttribute values applied to our enum class; or
  • load the resource string based on the ResourceKey in the DisplayStringAttribute; and
  • be expressible in XAML, both declaring one and as a databinding source.

Let’s take care of the third item first, since it will shape the public API more than the other two.

It is an enum’s nature to be static and constant, hence a class that aids in displaying it to the user is also likely to be static. We’ll also be using the EnumDisplayer to convert enum values and as a datasource. Before we can do anything though, we need to know the enum type we’ll be displaying. Ideally, this would mean passing the enum type in the constructor; because of the XAML requirement, however we need a property of type Type. We’ll add a constructor that takes a Type parameter as a convenience for those that like to write everything in code. So our initial public API looks thus:

public class EnumDisplayer : IValueConverter
{
  private Type type;
  private IDictionary displayValues;
  private IDictionary reverseValues;

  public EnumDisplayer()
  {
  }

  public EnumDisplayer(Type type)
  {
     this.Type = type;
  }

  public Type Type
  {
     get { return type; }
     set
     {
        if (!value.IsEnum)
           throw new ArgumentException("parameter is not an Enumermated type", "value");
        this.type = value;
     }
  }

  public ReadOnlyCollection<string> DisplayNames
  {
     get
     {
        this.displayValues =...
        return new List<string>((IEnumerable<string>)displayValues.Values).AsReadOnly();
     }
  }

  object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
  {
     return displayValues[value];
  }

  object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  {
     return reverseValues[value];
  }
}

Pretty straightforward public API: two properties, one being the type to generate strings for, and the other, the strings that we generated. The IValueConverter interface is implemented explicitly. The reverseValues dictionary maps the reverse of displayValues: displayValues goes from enum type to string, reverseValues goes from string to enum. This means that each enum value must have a unique display string; hardly unreasonable, since they have to have a unique name within the enum anyway.

The above public API allows us to declare an EnumDisplayer in XAML like so:

<Application.Resources>
        <sm:EnumDisplayer Type="{x:Type FlickrNet:ContentType}" x:Key="contentTypes">
</Application.Resources>

And use it as a data source and value converter:

<ComboBox ItemsSource="{Binding Source={StaticResource contentTypes},Path=DisplayNames}"
          SelectedValue="{Binding Path=Batch.Photos/ContentType,
                          Converter={StaticResource contentTypes}}" />

Well, that’s just awesome!

Let’s go back a bit and expand on that ‘…’ in the code for EnumDisplayer. That’s where all the real work happens. Since I don’t know the type at compile time, I use reflection to generate my two IDictionary instances when the DisplayValues property is first accessed. I also inspect the enum type provided for DisplayString attributes. All that code is below. It’s nothing special: most of it I found on the internet if I didn’t already know how to do it.

public ReadOnlyCollection<string> DisplayNames
{
 get
 {
    Type displayValuesType = typeof(Dictionary<,>)
                                .GetGenericTypeDefinition().MakeGenericType(typeof(string),type);
    this.displayValues = (IDictionary) Activator.CreateInstance(displayValuesType);

    this.reverseValues =
       (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>)
                .GetGenericTypeDefinition()
                .MakeGenericType(type, typeof(string)));

    var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static);
    foreach (var field in fields)
    {
       DisplayStringAttribute[] a = (DisplayStringAttribute[])
                                   field.GetCustomAttributes(typeof(DisplayStringAttribute), false);

       string displayString = GetDisplayStringValue(a);
       object enumValue = field.GetValue(null);

       if (displayString == null)
       {
          displayString = GetBackupDisplayStringValue(enumValue);
       }
       if (displayString != null)
       {
          displayValues.Add(enumValue, displayString);
          reverseValues.Add(displayString, enumValue);
       }
    }
    return new List<string>((IEnumerable<string>)displayValues.Values).AsReadOnly();
 }
}

private string GetDisplayStringValue(DisplayStringAttribute[] a)
{
     if (a == null || a.Length == 0) return null;
     DisplayStringAttribute dsa = a[0];
     if (!string.IsNullOrEmpty(dsa.ResourceKey))
     {
        ResourceManager rm = new ResourceManager(type);
        return rm.GetString(dsa.ResourceKey);
     }
     return dsa.Value;
}

Reflection code is always so ugly. I warned you it wasn’t pretty! See what framework developers have to go through to make code usable? So what’s happening here?

First, I dynamically create the two dictionaries as generic types. That begs the question: “Jason, why didn’t you use generics, wouldn’t that have been way easier? You’re such a pedantic loser!”

Good question. I couldn’t use them because of that third requirement that I imposed upon myself: XAML. There’s no easy way to declare a generic type in XAML, so I couldn’t use them.

Moving along: Next I grab the custom attributes, look for my DisplayStringAttribute and get the value from it in the helper method GetDisplayStringValue(). Notice I prefer the ResourceKey property before the Value property.

Then I add them to the dictionary and the reverseDictionary.

Astute readers should be asking this question by now: what about that call to GetBackupDisplayStringValue?

Right you are, Dear Reader! You’re so smart.

Alright, let’s go way back to the top of the article and address one of my assumptions: I assumed that I owned the enum type. That’s a great assumption to make when you’re coming up with trivial code examples for a blog post, but what about the real world? I got a mortgage! And WoW bills! And a flight to Japan to pay for!

It’s not an assumption that holds up under scrutiny. In fact, the chances you’ll be using an enum you own is probably slimmer than not owning the type. We all know everyone will be using the awesome DisplayStringAttribute once this blog post is published, but what about enums that were created B. DSA. (Before DisplayStringAttribute). Don’t worry, I got you covered.

To do that, and make it accessible in XAML, we need two things: a collection of enum display overrides and a way to tell the XAML parser that children of the EnumDisplayer get added to that collection. Here’s the rest of the implementation.

[ContentProperty("OverriddenDisplayEntries")]
public class EnumDisplayer : IValueConverter
{
   private Type type;
   private IDictionary displayValues;
   private IDictionary reverseValues;
   private List<EnumDisplayEntry> overriddenDisplayEntries;

    ...

   private string GetBackupDisplayStringValue(object enumValue)
   {
      if (overriddenDisplayEntries != null && overriddenDisplayEntries.Count > 0)
      {
         EnumDisplayEntry foundEntry = overriddenDisplayEntries.Find(delegate(EnumDisplayEntry entry)
                                          {
                                             object e = Enum.Parse(type, entry.EnumValue);
                                             return enumValue.Equals(e);
                                          });
         if (foundEntry != null)
         {
            if (foundEntry.ExcludeFromDisplay) return null;
            return foundEntry.DisplayString;

         }
      }
      return Enum.GetName(type, enumValue);
   }

   public List<EnumDisplayEntry> OverriddenDisplayEntries
   {
      get
      {
         if (overriddenDisplayEntries == null)
            overriddenDisplayEntries = new List<EnumDisplayEntry>();
         return overriddenDisplayEntries;
      }
   }
}

public class EnumDisplayEntry
{
   public string EnumValue { get; set; }
   public string DisplayString {  get; set; }
   public bool ExcludeFromDisplay { get; set; }
}

We decorate our EnumDisplayer class with the ContentProperty attribute that tells the XAML parser that anything contained in an EnumDisplayer element gets added to that property. Then we also need the property which is a List<EnumDisplayEntry>. The EnumDisplayEntry is a way to map an enum value to a new display string. The GetBackupDisplayStringValue() method is pretty straightforward: query the list for the given enum value to return the string or not if you want to exclude from being displayed. I suppose I should prefer the overridden value to the one provided in the DisplayStringAttribute but I’m jonesing for Guitar Hero, so I’m going to wrap up.

The above code enables you to provide your own strings for enum values, which we can express in XAML:

<sm:EnumDisplayer Type="{x:Type FlickrNet:ContentType}" x:Key="contentTypes">
    <sm:EnumDisplayEntry EnumValue="Photo" DisplayString="Photo (Default)"/>
    <sm:EnumDisplayEntry EnumValue="Screenshot" DisplayString="Screenshot"/>
    <sm:EnumDisplayEntry EnumValue="Other" DisplayString="Other"/>
</sm:EnumDisplayer>

Admittedly, these aren’t the most imaginative strings for these enum values, but that’s an actual snippet of XAML from an actual app.

There are still some things to address: WinForms and ASP.NET should be supported. Also, what about Flags enums? How should those be handled? Enums are surprising in their difficultly to show in UI properly. With the enum displayer class we have a good starting point for making a non-trivial problem of displaying enum values somewhat easier in XAML.

Posted in .NET, Missing .NET | 2 Comments »