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

前端 未结 5 1512
醉梦人生
醉梦人生 2021-01-02 12:05

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 v

相关标签:
5条回答
  • 2021-01-02 12:32

    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;
        //...
    }
    
    0 讨论(0)
  • 2021-01-02 12:40

    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?

    0 讨论(0)
  • 2021-01-02 12:44

    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.

    0 讨论(0)
  • 2021-01-02 12:45

    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);
    }
    
    0 讨论(0)
  • 2021-01-02 12:48

    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]}" />
    
    0 讨论(0)
提交回复
热议问题