65.9K
CodeProject is changing. Read more.
Home

Bindable Converter and Converter Parameter Revisited

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2 votes)

Sep 9, 2013

CPOL
viewsIcon

9310

This is an alternative for "Bindable Converter Parameter"

Introduction

The article http://www.codeproject.com/Articles/459958/Bindable-Converter-and-Converter-Parameter written by saved my day.

I just wanted to contribute making the code more robust....

Using the code

This is the usage in the XAML:

<TextBox 
                                               
Text="{myNameSpace:BindableConverter
                                          
Binding={Binding Path=...},
ConverterBinding={Binding Path=...},
UpdateSourceTrigger=PropertyChanged}" />

The Markup extension becomes:

public class BindableConverter : MarkupExtension
{
    public Binding Binding { get; set; }
    public IValueConverter Converter { get; set; }
    public Binding ConverterBinding { get; set; }
    public object ConverterParameter { get; set; }
    public Binding ConverterParameterBinding { get; set; }
    public UpdateSourceTrigger UpdateSourceTrigger { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        if (Converter == null && ConverterBinding == null)
            throw new Exception("Neither Converter nor ConverterBinding where provided");

        if (ConverterBinding == null && ConverterParameterBinding == null)
            throw new Exception("There is no point using this Extension. Please use standard Binding");

        MultiBinding multiBinding = new MultiBinding();
        multiBinding.UpdateSourceTrigger = UpdateSourceTrigger;
        multiBinding.Bindings.Add(Binding);
        if (ConverterBinding != null)
            multiBinding.Bindings.Add(ConverterBinding);
        if (ConverterParameterBinding != null)
            multiBinding.Bindings.Add(ConverterParameterBinding);

        BindableConverterAdapter adapter = new BindableConverterAdapter();
        adapter.Converter = Converter;
        adapter.ConverterParameter = ConverterParameter;

        multiBinding.Converter = adapter;
        return multiBinding.ProvideValue(serviceProvider);
    }
}

And the Adapter becomes:

public class BindableConverterAdapter : IMultiValueConverter
{
    public IValueConverter Converter { get; set; }
    public object ConverterParameter { get; set; }

    #region IMultiValueConverter Members

    /// <summary>
    /// ConverterBinding and ConverterParameterBinding take
    /// precedence over respectively Converter and ConverterParameter
    /// </summary>
    <returns>public object Convert(object[] values, Type targetType, 
                   object parameter, CultureInfo culture)
    {
        //values [0]: Binding
        //values [1]: IValueConverter or BindingParameter
        //values [2]: only BindingParameter

        IValueConverter converterBinding = values[1] as IValueConverter;
        if (converterBinding != null)
        {
            Converter = converterBinding;
            if (values.Length > 2)
                ConverterParameter = values[2];
        }
        else
            ConverterParameter = values[1];

        return Converter.Convert(values[0], targetType, ConverterParameter, culture);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, 
                  object parameter, CultureInfo culture)
    {
        return new[] {Converter.ConvertBack(value, targetTypes[0], null, culture)};
    }

    #endregion
}