Home .NET WPF: Converters as MarkupExtension

WPF: Converters as MarkupExtension

by admin

Converters are one of the most important features of the binding mechanism in WPF. They allow you to control how the anchor source is represented in the UI. In this article, I’ll show you how to make using converters in your XAML code a little easier.
Let’s look at the simplest example :

public class DateConverter : IValueConverter{public object Convert(object value, Type targetType, object parameter, CultureInfo culture){DateTime date = (DateTime)value;return date.ToShortDateString();}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){return null;}}

This is simple: the converter takes a DateTime value as input and converts it to a string. The reverse conversion is not provided.
The converter is used as follows :

<Window x:Class="TestConvertorMarkup.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:converters="clr-namespace:TestConvertorMarkup.Converters"Title="MainWindow" Height="350" Width="525"><Window.Resources><converters:DateConverter x:Shared="false" x:Key="dateConverter"/></Window.Resources><Label Content="{Binding Path=Date, Converter={StaticResource dateConverter}}" /></Window>

There’s nothing complicated here either, but the disadvantage of this approach is that you need to create a corresponding resource for each converter. Besides, we should either do this in a global resource dictionary or create our own resources for all the converters used in each XAML file, which is really bothersome when we have a lot of them. After some searching on the Internet, here I found an alternative solution.
First we modify the converter itself :

public class NumberToStringConverterExtension: MarkupExtension, IValueConverter{public object Convert(object value, Type targetType, object parameter, CultureInfo culture){DateTime date = (DateTime)value;return date.ToShortDateString();}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){throw new NotImplementedException();}public override object ProvideValue(IServiceProvider serviceProvider){if (_converter == null)_converter = new NumberToStringConverterExtension();return _converter;}private static NumberToStringConverterExtension _converter = null;}

After this modification, all you need to use it in XAML is :

<Label Content="{Binding Path=Date, Converter={converters:DateTimeToString}}" />

Of course, you must not forget to add the appropriate namespace "converters".
A nice bonus is that when you type, a list of available converters is shown :
WPF: Converters as MarkupExtension
Let’s not stop there, but in order to make writing new converters as easy as possible, let’s introduce a base class :

public abstract class ConvertorBase<T> : MarkupExtension, IValueConverterwhere T : class, new(){/// <summary>/// Must be implemented in inheritor./// </summary>public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture);/// <summary>/// Override if needed./// </summary>public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){throw new NotImplementedException();}#region MarkupExtension memberspublic override object ProvideValue(IServiceProvider serviceProvider){if (_converter == null)_converter = new T();return _converter;}private static T _converter = null;#endregion}

Now let’s inherit our DateConverter and implement the Convert method in it. The final version will look like this :

public class DateTimeToString : ConvertorBase<DateTimeToString>{public override object Convert(object value, Type targetType, object parameter, CultureInfo culture){DateTime date = (DateTime)value;return date.ToShortDateString();}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){return null;}}

The XAML code remains identical to the second example.
This way we can use simplified syntax in the XAML markup and the converter code remains almost unchanged.
P.S. Projects with examples can be downloaded here

You may also like