Skip to content

WPF IValueConverter and IMultiValueConverter

In this article I will show you how to convert values in WPF using IValueConverter and IMultiValueConverter.

Introduction

When you bind a data object of a View Model to a Dependency Property of your View the types must match together. If the types don’t match the compiler won’t give you an error during compilation as the UI is binded using reflection at runtime and thus no compile time type checking can be performed. Instead your binding will simply not work and thus won’t show you the data you would like to see.

Because Binding errors are neither reported by a compiler nor lead to an immediate crash of the application during startup this is a common error source which is not recognized during test phase and propably get delivered to the customer. 

Thus, my good advice is: Always pay attention to the types you bind to!

What to do if types missmatch?

If a type missmatches you have two possibilties:

  • Change the type in your View Model to match the type of the Dependency Property
  • Add a Value Converter

If the first possibility does not work for you as you maybe cannot change the type of your View Model property you will need to add a Value Converter.

Concept of Value Conversion

Value conversion is performed between the View Model and the View to match the types together.

The conversion can be done into both directions. It depends of the type of your binding. If you bind one way from View Model to View you only need to provide a conversion from your View Model to your View (i.e. from Color to Brush).

There are two Interface Types for Value Converters:

  • IValueConverter
  • IMultiValueConverter

IValueConverter is used to convert the type of one property into your target property to be bound to. Most of the time you will use the IValueConverter interface. However, in some situations it can happen that you need to convert two or more properties into your target property. In this case you can derive from IMultiValueConverter. A common use case of IMultiValueConverter is when you need a reference to your View Model in addition to your property to be converted passed into the Converter.

Usage of IValueConverter

In our example above we have a property ‘Background’ of type ‘Color’ in our View Model and a property ‘Background’ in the WPF Button Control which should be bound to. If we try to bind to the property directly without conversion everything will compile without errors.

<Grid> <Button Content="Push me" Background="{Binding Background}" Width="200" Height="80"/> </Grid>
Code language: HTML, XML (xml)

The application will even run without a crash. The only thing you will see is an error in your output window in visual studio.

Value produced by BindingExpression is not valid for target property.

And of course the color will not be applied to your Button.

To solve this issue we need to implement a class derived from IValueConverter.

public class ColorToBrushConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return new SolidColorBrush((Color)value); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
Code language: C# (cs)

There are two methods to be implemented from IValueConverter:

  • Convert – Conversion from View Model Property to View Property
  • ConvertBack – Conversion from View Property to View Model Property

With the following parameters:

  • value – value to be converted
  • targetType – type of the target property. In our case it is the type ‘Brush’ for the Convert method
  • parameter – you can pass a parameter to your converter. However, this can only be a constant parameter like a string or a number. You cannot bind to a value. If you need another value for conversion that needs to be passed via binding you will need to use IMultiValueConverter.
  • culture – culture info from your view. This can be importent if you need to format a date/time string.

The implementation of the Convert method just creates a SolidColorBrush object with the color passed in. As we have a one way binding we don’t need to implement the ConvertBack method and thus just throw an exception.

In order to use the Converter we need to declare the converter in our resource section and use it inside the binding to the Background Dependency Property.

<Window x:Class="Playground.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Playground" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Window.DataContext> <local:MainWindowModel/> </Window.DataContext> <Window.Resources> <local:ColorToBrushConverter x:Key="ColorToBrushConverterKey"/> </Window.Resources> <Grid> <Button Content="Push me" Background="{Binding Background, Converter={StaticResource ColorToBrushConverterKey}}" Width="200" Height="80"/> </Grid> </Window>
Code language: HTML, XML (xml)

The parameter can be passed by passing a value to the Binding Prameter ConverterParameter. In the listing below I simply passed the value 10. As mentioned above you can only pass constant values but no binding.

<Button Content="Push me" Background="{Binding Background, Converter={StaticResource ColorToBrushConverterKey}, ConverterParameter=10}" Width="200" Height="80"/>
Code language: HTML, XML (xml)

Usage of IMultiValueConverter

To demonstrate the IMultiValueConverter we use the example above and just pass the View Model in addition to the value. In our use case it makes no sense as we don’t need it to convert from color to brush but in many other cases it is necessary to have the view model.

Now you might come to the question: why don’t we simply bind to the view model and leave out the Background Property because the View Model has the Background property and we could simply access it through the View Model. The answer is: we need the change notification when the Background property of the View Model changes so that the WPF binding automation can update the Button color immediately. If we would only bind to the View Model WPF wouldn’t get a change notification of the Background property and thus would never update the Button Background property.

In the listing below we derive from IMultiValueConverter. The only difference compared to IValueConverter is that the Convert method now takes an array of values.

public class MultiColorToBrushConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if (values.Length < 2) return null; var vm = (MainWindowModel)values[0]; var color = (Color)values[1]; //here could be some addition logic to evaluate something in the view model return new SolidColorBrush((Color)color); } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
Code language: C# (cs)

To use the converter we need to declare it in the resource dictionary and use it inside the binding expression.

<Window x:Class="Playground.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Playground" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Window.DataContext> <local:MainWindowModel/> </Window.DataContext> <Window.Resources> <local:MultiColorToBrushConverter x:Key="MultiColorToBrushConverterKey"/> </Window.Resources> <Grid> <Button Content="Push me" Width="200" Height="80"> <Button.Background> <MultiBinding Converter="{StaticResource MultiColorToBrushConverterKey}"> <Binding /> <Binding Path="Background"/> </MultiBinding> </Button.Background> </Button> </Grid> </Window>
Code language: HTML, XML (xml)

The first parameter passed into the binding is the View Model (if no path is passed it binds to itself). The second parameter is the path to the property ‘Background’.

Copyright (c) by Thomas Kemp, 2021