📜 ⬆️ ⬇️

WPF: MarkupExtension Converters

Converters are one of the most important features of the binding mechanism in WPF. They allow you to control how the binding source is presented in the UI. In this article I will show how to simplify the use of converters in XAML code a little.

Consider 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; } } 

Everything is simple: the input converter receives a value of type DateTime and converts it into a string. 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> 

Here, too, there is nothing difficult, however, a minus of such an approach - for each converter you need to create a corresponding resource. Moreover, one should either do it in the global resource dictionary, or in each XAML file one should create its own resources for all the converters used, which is very annoying when there are many such converters. 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}}" /> 

Naturally. you need to remember to add the appropriate converters namespace.
A nice bonus is that when typing displays a list of available converters:

Let's not rest on our laurels, but in order to simplify the writing of new converters as much as possible, we introduce the base class:
 public abstract class ConvertorBase<T> : MarkupExtension, IValueConverter where 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 members public override object ProvideValue(IServiceProvider serviceProvider) { if (_converter == null) _converter = new T(); return _converter; } private static T _converter = null; #endregion } 

Now our DateConverter will inherit from it 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.

Thus, we were able to use the simplified syntax in XAML markup, and the converter code has not changed much.

PS Projects with examples can be downloaded here .

Source: https://habr.com/ru/post/140876/


All Articles