Three things you probably didn’t know about XAML converters #1: Combining ValueConverters

It’s time again for a small series of posts, this time concerning XAML ValueConverters! Most of this stuff will work in all XAML dialects, meaning you can also use it in WPF desktop applications, but of course it’s also quite useful for Windows Phone and Windows Store projects!

One of the shortcomings of usual ValueConverters is that they simply convert one value into another, there’s no way to plug in multiple values and get a combined, single result out (apart from passing parameters, which is a topic I’m planning to cover in a separate blog post). For this, Microsoft invented MultiConverters. Those of you who learned WPF / Silverlight in a course or through a book will probably have heard about this, while it might be a totally new topic for all the others who are still learning by doing.

Implementation is simple: Let’s assume we have a window containing a list of data items, and a button that allows editing those items. However, users shall be allowed to click that button only if they are logged in as administrator, AND if there are items available in the list. Of course this is a rather simplified example that can be solved in a thousand different ways, but just for demonstration let’s try to bind the button’s IsEnabled property to two single properties:

  • First, to an IsAdmin flag that exists somewhere inside the Viewmodel and that indicates whether the current user has administrator credentials
  • In addition, to the number of list items – this could be realized through some kind of CollectionCountToBooleanConverter that returns true only if a given collection contains one or more items, and false if there are no collection items existent

The question is: How to bind the button’s IsEnabled property to two separate values? This is where MultiBinding comes into play! For this, we need a small MultiValueConverter that (in our case) combines several boolean values and returns true only if all of the input values are true. Such a converter would look very similar to a standard ValueConverter, but it implements the IMultiValueConverter interface (instead of IValueConverter) and its Convert method accepts an array of input values (instead of just one).

public class MultiBooleanConverter : IMultiValueConverter
{
	public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
	{
		foreach (object value in values)
		{
			if (value is bool)
			{
				if ((bool)value == false)
				{
					return false;
				}
			}
		}
		return true;
	}

	public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
	{
		throw new NotImplementedException();
	}
}

Or in short, as a one-liner that also simply checks if all input values are not false:

public class MultiBooleanConverter : IMultiValueConverter
{
	public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
	{
		return values.Where(value => value is bool).All(value => (bool) value != false);
	}

	public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
	{
		throw new NotImplementedException();
	}
}

Usage of such a MultiBooleanConverter in XAML code is even easier. Of course, we first need to register it as static resource:

<Page.Resources>
	<MultiBooleanConverter x:Key="MultiBooleanConverter"/>
</Page.Resources>

and then reference it by using MultiBinding:

<Button Command="{Binding EditCommand}" Content="Edit">
	<Button.IsEnabled>
		<MultiBinding Converter="{StaticResource MultiBooleanConverter}">
			<Binding Path="IsAdmin"/>
			<Binding Path="ListItems" Converter="{StaticResource CollectionCountToBooleanConverter}"/>
		</MultiBinding>
	</Button.IsEnabled>
</Button>

As planned, the button will only be enabled if both requirements are fulfilled! Of course, it’s easy now to adapt the Converter class to, for example, realize other combinations of boolean values (e.g., only one of the values must be true) or combine other data types (e.g., first, middle, and last name of a person as string input values could be combined to one single string output value that contains the person’s full name). The second code example shown above (the one containing only one LINQ-statement) might be a good starting point, because it allows to simply change the data types and requirements to be checked, in order to quickly create further MultiConverters on demand.