WPF: Dictionary Value Converter

10 באוגוסט 2011

תגיות: , , ,
אין תגובות

What’s the story?

You want to convert an enum value to a bitmap image.

That’s easy, here’s a solution

Usually you would simply create a new value converter which has some custom code (e.g. a switch –case statement) to convert from the enum value to the relevant image.

Is there a better solution?

How many times have you written this kind of converter, the kind that takes a value and maps it to another value?

Well, no more!

I present to you: DictionaryValueConverter. A Converter that lets you define a collection of key-value pairs and do the mapping for you.

So, how can I use this converter?

The following code provides a common usage of this converter. Here I map three enum values to three different bitmap images. Each value in the Values property is another image which is mapped by its x:Key.

<converters:DictionaryValueConverter x:Key="propertyTypeToImage">
    <converters:DictionaryValueConverter.Values>
        <BitmapImage x:Key="{x:Static local:PropertyType.Name}"
                     UriSource="Name.png" />
        <BitmapImage x:Key="{x:Static local:PropertyType.Age}"
                     UriSource="Age.png" />
        <BitmapImage x:Key="{x:Static local:PropertyType.Phone}"
                     UriSource="Phone.png" />
    </converters:DictionaryValueConverter.Values>
</converters:DictionaryValueConverter>

This is SO COOL, can I use it also to convert Booleans to Visibility?

Well, yes and no.

Theoretically, it will work. There is nothing in the code which prevents it.

Practically, you need a way to specify the “true” and “false” Boolean values as the keys.

Unfortunately, XAML 2006 doesn’t allow x:Key to have complex values (using property element syntax). This was fixed in XAML 2009, but WPF doesn’t support it yet.

To work around it you can define constants for the “true” and “false” values and use x:Static markup extension to provide the keys.

For example:

public static class BooleanValues
{
    public const bool True = true;
    public const bool False = false;
}

 

<converters:DictionaryValueConverter x:Key="booleanToVisibilityConverter">
    <converters:DictionaryValueConverter.Values>
        <Visibility x:Key="{x:Static local:BooleanValues.True}">Visible</Visibility>
        <Visibility x:Key="{x:Static local:BooleanValues.False}">Collapsed</Visibility>
    </converters:DictionaryValueConverter.Values>
</converters:DictionaryValueConverter>

 

So, how is it implemented?

Like this:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Data;

namespace Common.Converters
{
    public class DictionaryValueConverter : IValueConverter
    {
        /// <summary>
        /// Store the key type.
        /// Setting this property is needed if your key is an enum and  
        /// </summary>
        public Type KeyType { get; set; }

        /// <summary>
        /// Store the key-value pairs for the conversion
        /// </summary>
        public Dictionary<object, object> Values { get; set; }

        public DictionaryValueConverter()
        {
            Values = new Dictionary<object, object>();
        }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            // if key type is not set, get it from the first dictionary value, usually it's the same for all the keys
            if (KeyType == null)
            {
                KeyType = Values.Keys.First().GetType();
            }

            // if key type is an enum
            if (KeyType.IsEnum)
            {
                // convert integral value to enum value
                value = Enum.ToObject(KeyType, value);
            }

            // if dictionary contains the requested key
            if (Values.ContainsKey(value))
            {
                // return the relevant value
                return Values[value];
            }

            // otherwise, don't return a value, this will fall back to the binding FallbackValue
            return DependencyProperty.UnsetValue;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            // no support for converting back
            return DependencyProperty.UnsetValue;
        }
    }
}

You can download a demo application here.

That’s it for now,
Arik Poznanski.

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. (*) שדות חובה מסומנים