Table of Contents
Understanding MultiBinding
MultiBinding in WPF allows you to bind a property on a target object to a list of source properties and then apply logic to produce a final value. This is useful when the property depends on a combination of values rather than a single source property. Essentially, we’ll write a custom Converter class that inherits from IMultiValueConverter to return a single value based on multiple input parameters.
Creating Our Custom Converter Class
In this example, I want a Button in my UI to be enabled or disabled based on 3 different values. Two are booleans in the ViewModel, and the third is a Text.Length property from an entry box elsewhere in the UI. Here’s the code for the converter, which I’ve named EnableRenameAllButtonConverter:
using System; using System.Globalization; using System.Windows.Data; namespace RENAMinator.Converters { public class EnableRenameAllButtonConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { // Check that we have exactly three values and they are of the expected types. if (values.Length == 3 && values[0] is bool && values[1] is bool && values[2] is int) { bool anyItemsChecked = (bool)values[0]; bool anyCheckedItemHasValidNewName = (bool)values[1]; int textLength = (int)values[2]; // Return true if all three conditions are met. return anyItemsChecked && anyCheckedItemHasValidNewName && textLength > 0; } return false; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotSupportedException("ConvertBack not supported."); } } }
Here, the Convert object method is taking in a parameter array as its first argument. We check to make sure there are exactly 3 values, and then we verify the data type for each of these values (2 bools and 1 int). Then, we return a single boolean value based on the truth of all 3 conditions.
NOTE: Data Types
It’s important to verify that the custom logic in our Convert method yields a return type that matches the property type of the UI element we’re binding to. In this case, it’s a Button’s IsEnabled property, which is boolean (so we’re returning true / false), but you can return any type you’d like, such as Visibility (Visible, Hidden, Collapsed), string, int, or literally any other type you can dream of.
Declaring Our Converter in XAML
We need to first add our custom converter to the XAML resource it’s going to be used in. In this case, it’s a UserControl, but it can be defined in any XAML resource, such as Window.
<UserControl.Resources> <converters:EnableRenameAllButtonConverter x:Key="EnableRenameAllButtonConverter"/> </UserControl.Resources>
Defining the MultiBinding in XAML
<Button Grid.Column="0" Margin="5,5,5,5" Padding="5" Command="{Binding RenameCommand}" Content="RENAME ALL"> <Button.IsEnabled> <MultiBinding Converter="{StaticResource EnableRenameAllButtonConverter}"> <Binding Path="AnyItemsChecked" /> <Binding Path="AnyCheckedItemHasValidNewName" /> <Binding Path="Text.Length" ElementName="txtFindWhat" /> </MultiBinding> </Button.IsEnabled> </Button>
Here, inside a <Button.IsEnabled> block, we’re defining the StaticResource to use as our MultiBinding Converter by including it inside a <MultiBinding> block. Then, we tell our custom converter which three values to use. In this case, the first two are boolean values in our ViewModel (or code-behind), and the third is the Text.Length property from an entry box elsewhere on the form.
And that’s it! Our Button is now enabled or disabled based on the 3 properties passed to our custom converter!