Providing your own drop-down list in the WPF Property Grid

Suppose you’ve got a property that you want users to edit in the WPF Elements PropertyGrid control, but rather than the user being able to enter any old rubbish you want to present them with a drop-down list of choices. One simple way to do this is to make the property an enum, but what if the list of choices isn’t known at compile time — for example, if the list comes from a database?

Well, a friend of ours has a feature request in to Microsoft for dynamic enums, where you can choose the enum values at run time, but just between you and me, I wouldn’t hold my breath for that one. In the meantime, fortunately, you can solve the problem old skool. Here’s how.

I’ve written elsewhere about the queer old dynamic pseudo-type system that lives in the System.ComponentModel cave of wonders. One of the many things you can do with this subsystem is to describe a standard set of values, even for properties or types that aren’t enums. An example of this is how in XAML you can write, say, Background=”HotPink” instead of <Button.Background><SolidColorBrush><Color R=”255″ …etc…. WPF defines a standard set of values for the Brush type so that you can specify common brushes by name, even though Brush isn’t an enum.

The secret lies in the TypeConverter class. TypeConverter, despite its name, isn’t just about converting between types. It also has a GetStandardValues() method which you can override to — you guessed it — provide a standard set of values. That standard set of values can come from anywhere, so you can make it up at runtime.

Let’s see this in action. Suppose we have a Penguin object, and we want users to be able to enter the penguin’s species, but we want to assist users by giving them a list of known species to choose from. Since new species of penguin are discovered all the time in the depths of the Amazon rainforest, we don’t want to code this up as an enum — it needs to be a string but it needs to have standard values.

Enter the TypeConverter. We have to create a class that derives from TypeConverter and overrides two methods: GetStandardValuesSupported and GetStandardValues. The first one tells the UI that there are standard values — without it, the grid will assume that there are no standard values and will just display a text box. The second tells the UI what the standard values are. Here’s the implementation:

internal class PenguinSpeciesConverter : TypeConverter
{
  public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
  {
    return true;  // required if you want standard values
  }
 
  public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
  {
    // Ignoring caching and other performance issues
    string[] species = GetSpeciesFromDatabase();
    return new StandardValuesCollection(species);
  }
}

So far so good. Now we need to specify that this type converter applies to our Penguin.Species property. If we had a separate PenguinSpecies type, we could do this at the type level, but since we’re making Species a string, that won’t work. (Technically, it is possible to associate the PenguinSpeciesConverter with the string type, but it would be a really, really bad idea, because it would affect every string in your application.) Instead, we need to specify the type converter at the property level by applying TypeConverterAttribute to the property:

public class Penguin : INotifyPropertyChanged
{
  [TypeConverter(typeof(PenguinSpeciesConverter))]  // hooks up the type converter
  public string Species { /* implementation omitted */ }
}

And this is all you need to do! You don’t need to specify a PropertyEditor in the PropertyGrid control declaration: the grid detects that there is a standard set of values for the Species property and automatically uses a drop-down instead of a text box.

What if your property was of a different type, such as Brush? That is where the convert-y bits of TypeConverter comes in. You can implement GetStandardValues() to return strings, then implement CanConvertFrom and ConvertFrom to convert those strings to the “real” type. Leave a comment if you need more info on this and I’ll try to post some more details.

Want to give it a go? The PropertyGrid control is just one of 35+ stunning controls in our WPF Elements suite. Download the trial here or get free controls here!

Leave a Reply

Archives

Join our mailer

You should join our newsletter! Sent monthly:

Back to Top