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

妖精的绣舞 提交于 2019-11-30 13:55:33

In most cases, you can safely make ConvertBack just throw NotImplementedException.

Indeed, you just haven't got enough information to recreate the source value from its part!

If you really need the back conversion (e.g., if you use two-direction binding), I would split the property into 3 strings in the view model (the class used in DataContext), and bind to them separately.

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;
    //...
}

Would you be better off using an IMultiValueConverter and a MultiBinding?

public interface IMultiValueConverter
{
    object Convert(object[] values, Type targetType, object parameter, CultureInfo culture);

    object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture);
}

In this case, if you really want to be able to edit the constituents, you could represent your number by a more complex object which allows you to access its 4 constituent parts through an indexer. That way it's just a simple binding and the object that keeps the 4 parts is accessed and can piece together the whole number:

public class MyNumber {
  public int this[int index] {
    get { /**/ } set { /**/ }
  }
  public string FullNumber { get { /**/ } }
}

<TextBox Text={Binding MyNumber[0]}" />
Ujjwal

I just built up quick sample. Please check if you are looking for the same. This is working at my end.

  • Xaml Code

    <StackPanel>
        <TextBox Text="1/2/3/4" x:Name="txtSource"></TextBox>
        <TextBox Text="{Binding ElementName=txtSource, 
                                Path=Text, 
                                Converter={StaticResource txtConv},
                                ConverterParameter='0'}" 
                 x:Name="txtTarget1"></TextBox>
        <TextBox Text="{Binding ElementName=txtSource, 
                                Path=Text, 
                                Converter={StaticResource txtConv},
                                ConverterParameter='1'}"
                 ></TextBox>
        <TextBox Text="{Binding ElementName=txtSource, 
                                Path=Text, 
                                Converter={StaticResource txtConv},
                                ConverterParameter='2'}" ></TextBox>
        <TextBox Text="{Binding ElementName=txtSource, 
                                Path=Text, 
                                Converter={StaticResource txtConv},
                                ConverterParameter='3'}"></TextBox>
    </StackPanel>
    
  • Code Behind

    public class TextConverter : IValueConverter {
        #region IValueConverter Members
    
        public object Convert (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            string input = (string)value;
            char[] sep = {'/'};
            string[] iparray = input.Split (sep);
            int index = Int32.Parse((string)parameter);
    
            return iparray[index];
        }
    
        public object ConvertBack (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            throw new NotImplementedException ();
        }
    
        #endregion
    }
    

However, I couldn't understand the exact issue with ConvertBack method. Could you please elaborate on this?

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!