Wednesday 8 October 2014

Binding ConverterParameter

There have been numerous cases where I've wanted to bind a ConverterParameter on a converter instance to either a property on another object or to a property on my view model.

XAML Binding
<Label Content="{Binding BoundedValue
            , Converter={StaticResource valueIfNullConverter}
            , ConverterParameter={Binding DefaultNullValue}}"/>
Converter
    public class ValueIfNullConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return value ?? System.Convert.ToString(parameter);
        }
    }

Only to find this failing at runtime with the following exception:

A 'Binding' cannot be set on the 'ConverterParameter' property of type 'Binding'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.

This therefore implies the ConverterParameter property isn't exposed as a DependencyProperty and therefore can't be bound to.

To overcome this problem we can use a MultiBinding along with a multi-value converter whereby we bind the "values" of the converter to both the data source and converter parameter properties as follows:

        <Label>
            <Label.Content>
                <MultiBinding Converter="{StaticResource valueIfNullConverter}">
                    <Binding Path="BoundedValue" />
                    <Binding Path="DefaultNullValue" />
                </MultiBinding>
            </Label.Content>
        </Label>
And changing our converter to a multi-value converter:
    public class ValueIfNullConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (values != null && values.Length == 2)
            {
                return values[0] ?? System.Convert.ToString(values[1]);
            }

            return values;
        }
    }
In the multi-value converter above, the bound value and parameter are now accessible inside the 'values' collection argument instead of accessing the parameter through the 'parameter' argument.

No comments:

Post a Comment