Windows 8 XAML Tips - Combining Converters

By Fons Sonnemans, 23-12-2013

XAML is a declarative UI language; it's most powerful feature is surely data binding. In XAML you can set a converter on any binding. You use this when you need to display data in a format that differs from how it is stored. But you can only set ONE converter. So if you for instance want to convert a date using a FormatConverter and you want to convert the result to uppercase using a UppercaseConverter you are stuck. To solve this problem I have created a ValueConverterGroup class. It is a converter which contains multiple converters, it is a List of IValueConverter objects and it implements the IValueConverter interface. The Convert() method calls the Convert() method of all containing value converters. I haven't implement the ConvertBack() method because I won't be using it.

ValueConverterGroup

using System;
using System.Collections.Generic;
using System.Linq;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;

namespace ReflectionIT.Windows8.Converters {

    public class ValueConverterGroup : List<IValueConverter>, IValueConverter {

        public object Convert(object value, Type targetType, object parameter, 
                                  string language) {
            return this.Aggregate(value, (current, converter) =>
                current == DependencyProperty.UnsetValue ? 
                    current : 
                    converter.Convert(current, targetType, parameter, language)
            );
        }

        public object ConvertBack(object value, Type targetType, object parameter, 
                                  string language) {
            System.Diagnostics.Debugger.Break(); // Not Implemented
            throw new NotImplementedException();
        }
    }
}

Example

The following sample page contains a DatePicker control and two TextBlock controls. The Text property of the TextBlocks are databound to the Date property of the DatePicker. The first (red) TextBlock uses a FormatConverter to convert the date to dd-MMM-yyyy string. The second (blue) TextBlock uses my ValueConverterGroup to combine a FormatConverter and an UppercaseConverter.

The two converters are static resources which are defined in the Page resources.

<Page x:Class="ConvertersDemo.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:ConvertersDemo"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:c="using:ReflectionIT.Windows8.Converters"
      mc:Ignorable="d">


    <Page.Resources>
        <c:FormatConverter x:Key="DateFormat"
                           FormatString="{}{0:dd-MMM-yyyy}" />

        <c:ValueConverterGroup x:Key="UppercaseDateFormat">
            <c:FormatConverter FormatString="{}{0:dd-MMM-yyyy}" />
            <c:UppercaseConverter />
        </c:ValueConverterGroup>
    </Page.Resources>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <DatePicker x:Name="datePicker"
                    HorizontalAlignment="Left"
                    VerticalAlignment="Top"
                    Margin="136,85,0,0" />
        <TextBlock HorizontalAlignment="Left"
                   TextWrapping="Wrap"
                   Text="{Binding Date, Converter={StaticResource DateFormat},
                                   ElementName=datePicker}"
                   VerticalAlignment="Top"
                   Margin="136,164,0,0"
                   FontSize="64"
                   Foreground="Red" />
        <TextBlock HorizontalAlignment="Left"
                   TextWrapping="Wrap"
                   Text="{Binding Date, Converter={StaticResource UppercaseDateFormat},
                                   ElementName=datePicker}"
                   VerticalAlignment="Top"
                   Margin="136,283,0,0"
                   FontSize="64"
                   Foreground="Blue" />
    </Grid>
</Page>

As you can see in the next screenshot the blue TextBlock is showing the date in a dd-MMM-yyyy format in uppercase.

CombiningConverters

FormatConverter

The code of the FormatConverter class used in the example.

using System;
using System.Globalization;
using Windows.UI.Xaml.Data;

namespace ReflectionIT.Windows8.Converters {

    public class FormatConverter : IValueConverter {

        public string FormatString { get; set; }

        public object Convert(object value, Type typeName, object parameter, 
                                   string language) {

            string formatterString = (parameter as String) ?? FormatString;

            if (!string.IsNullOrEmpty(formatterString)) {
                return string.Format(formatterString, value);
            }

            return System.Convert.ToString(value);
        }

        public object ConvertBack(object value, Type typeName, object parameter, 
                                  string language) {
            System.Diagnostics.Debugger.Break(); // Not Implemented
            throw new NotImplementedException();
        }

    }
}

UppercaseConverter

The code of the UppercaseConverter class used in the example.

using System;
using Windows.UI.Xaml.Data;

namespace ReflectionIT.Windows8.Converters {

    class UppercaseConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, 
                                   string language) {
            return System.Convert.ToString(value).ToUpper();
        }

        public object ConvertBack(object value, Type targetType, object parameter, 
                                   string language) {
            System.Diagnostics.Debugger.Break(); // Not Implemented
            throw new NotImplementedException();
        }
    }
}

 

Closure and download

I hope you like my solution. Combining multiple converters is now very easy. You can download my code below.

Cheers,

Fons

Leave a Comment

Leave a Comment
Name
Comment
1 + 3 =

1 Comments

  • Geert van Horrik
    24 dec 2013 03:15
    I think it is better to return Windows.UI.Xaml.DependencyProperty.UnsetValue instead of throwing an exception in the ConvertBack method (for performance reasons).

All postings/content on this blog are provided "AS IS" with no warranties, and confer no rights. All entries in this blog are my opinion and don't necessarily reflect the opinion of my employer or sponsors. The content on this site is licensed under a Creative Commons Attribution By license.