Get the Source value in ConvertBack() method for IValueConverter implementation in WPF binding

tom picture tom · Aug 15, 2011 · Viewed 14.3k times · Source

I am binding a dependency property to textboxex in WPF. The property is a string that has some values separated by '/' (example: "1/2/3/4" ). I need to bind individual values to separate textboxes which is fine with following implementation of Convert() method:

public object Convert(object value, Type targetType, object parameter,System.Globalization.CultureInfo culture)
{
  if (!string.IsNullOrEmpty(value as string))
  {
    String[] data = (value as string).Split('/');
    return data[Int16.Parse(parameter as string)];
  }
  return String.Empty;
}

And I am using the ConverterParameter in xaml to specify the position of wanted value. However, the problem is with ConvertBack() method. I do not know, how to get the source value so I could just add or change just one value in the string (on the specified position).

Thanks for any help.

Answer

Fredrik Hedblad picture Fredrik Hedblad · Aug 15, 2011

Update

You have probably solved your issue already with the help of Vlad, I just thought I should add another way of actually getting the source value in the converter.

First you could make your converter derive from DependencyObject so you can add a Dependency Property to it which we shall bind to

public class MyConverter : DependencyObject, IValueConverter
{
    public static DependencyProperty SourceValueProperty =
        DependencyProperty.Register("SourceValue",
                                    typeof(string),
                                    typeof(MyConverter));
    public string SourceValue
    {
        get { return (string)GetValue(SourceValueProperty); }
        set { SetValue(SourceValueProperty, value); }
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        //...
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        object targetValue = value;
        object sourceValue = SourceValue;
        //...
    }
}

Unfortunately, a Converter doesn't have a DataContext so the Binding won't work out of the box but you can use Josh Smith's excellent DataContextSpy: Artificial Inheritance Contexts in WPF

<TextBox>
    <TextBox.Resources>
        <src:DataContextSpy x:Key="dataContextSpy" />
    </TextBox.Resources>
    <TextBox.Text>
        <Binding Path="YourProperty"
                 ConverterParameter="1">
            <Binding.Converter>
                <src:MyConverter SourceValue="{Binding Source={StaticResource dataContextSpy},
                                                       Path=DataContext.YourProperty}"/>
            </Binding.Converter>
        </Binding>
    </TextBox.Text>
</TextBox>

End of Update

Dr.WPF has an elegant solution to this, see the following thread
The way to access binding source in ConvertBack()?

Edit

Using the solution by Dr.WPF, you could supply both the string index and the source TextBox to the converter with this (perhaps a little verbose) sample code

<TextBox dw:ObjectReference.Declaration="{dw:ObjectReference textBoxSource}">
    <TextBox.Text>
        <Binding Path="YourStringProperty"
                 Converter="{StaticResource YourConverter}">
            <Binding.ConverterParameter>
                <x:Array Type="sys:Object">
                    <sys:Int16>1</sys:Int16>
                    <dw:ObjectReference Key="textBoxSource"/>
                </x:Array>
            </Binding.ConverterParameter>
        </Binding>
    </TextBox.Text>
</TextBox>

And then you could later access both the index and the TextBox in the ConvertBack method

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    object[] parameters = parameter as object[];
    short index = (short)parameters[0];
    object source = (parameters[1] as TextBox).DataContext;
    //...
}