In trying to solve an issue Im having in another project - Ive created the following example to replicate the issue.
The idea is that when the user enters new values, via the slider or textbox, those values should then be "ConvertedBack" via the convertor, and the source updated. I don't seem to be seeing this though, I believe due to the fact that InternalRep's properties are being written to, but not informing the bindexpression for the InternalRepProperty.
What is the best way to go about solving this problem?
One method I tried was to handle the sliders ValueChanged event, but this caused the convertor to ... ConvertBack then Convert then ConvertBack then Convert, not sure why.
When the user changes a value, I need the convertor to only ConvertBack to update the source, and nothing else, .. is this possible?
TextSplitter XAML
<ContentControl x:Class="WpfApplication23.TextSplitter"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:local="clr-namespace:WpfApplication23"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UniformGrid Columns="3" Rows="2">
<TextBox Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:TextSplitter}},
Path=InternalRep.First, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
<TextBox Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:TextSplitter}},
Path=InternalRep.Second, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
<TextBox Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:TextSplitter}},
Path=InternalRep.Third, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
<Slider Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:TextSplitter}},
Path=InternalRep.First, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Maximum="255" />
<Slider Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:TextSplitter}},
Path=InternalRep.Second, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Maximum="255" />
<Slider Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:TextSplitter}},
Path=InternalRep.Third, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Maximum="255" ValueChanged="OnSliderChnaged" />
</UniformGrid>
</ContentControl>
TextSplitter C#
public class InternalRep
{
public int First { get; set; }
public int Second { get; set; }
public int Third { get; set; }
};
public class LettersToInternalRepMultiConvertor : IMultiValueConverter
{
public object Convert(object[] values, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
InternalRep ir = new InternalRep()
{
First = (int)(char)values[0],
Second = (int)(char)values[1],
Third = (int)(char)values[2],
};
return ir;
}
public object[] ConvertBack(object value, Type[] targetTypes,
object parameter, System.Globalization.CultureInfo culture)
{
InternalRep ir = (InternalRep)value;
if (ir != null)
{
return new object[]
{
(char)ir.First,
(char)ir.Second,
(char)ir.Third
};
}
else
{
throw new Exception();
}
}
}
public partial class TextSplitter : ContentControl
{
public static readonly DependencyProperty FirstProperty = DependencyProperty.Register(
"First", typeof(char), typeof(TextSplitter));
public static readonly DependencyProperty SecondProperty = DependencyProperty.Register(
"Second", typeof(char), typeof(TextSplitter));
public static readonly DependencyProperty ThirdProperty = DependencyProperty.Register(
"Third", typeof(char), typeof(TextSplitter));
public static readonly DependencyProperty InternalRepProperty = DependencyProperty.Register(
"InternalRep", typeof(InternalRep), typeof(TextSplitter));
BindingExpressionBase beb = null;
public TextSplitter()
{
InitializeComponent();
MultiBinding mb = new MultiBinding();
mb.Mode = BindingMode.TwoWay;
mb.Bindings.Add(SetBinding("First"));
mb.Bindings.Add(SetBinding("Second"));
mb.Bindings.Add(SetBinding("Third"));
mb.Converter = new LettersToInternalRepMultiConvertor();
beb = SetBinding(InternalRepProperty, mb);
}
Binding SetBinding(string _property)
{
Binding b = new Binding(_property);
b.Mode = BindingMode.TwoWay;
b.Source = this;
return b;
}
public char First
{
get { return (char)GetValue(FirstProperty); }
set { SetValue(FirstProperty, value); }
}
public char Second
{
get { return (char)GetValue(SecondProperty); }
set { SetValue(SecondProperty, value); }
}
public char Third
{
get { return (char)GetValue(ThirdProperty); }
set { SetValue(ThirdProperty, value); }
}
}
MainWindow XAML
<Window x:Class="WpfApplication23.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication23"
Title="MainWindow" Height="640" Width="800" WindowStartupLocation="CenterScreen">
<StackPanel>
<local:TextSplitter First="{Binding A, Mode=TwoWay}"
Second="{Binding B, Mode=TwoWay}"
Third="{Binding C, Mode=TwoWay}"/>
</StackPanel>
</Window>
MainWindow Code
namespace WpfApplication23
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
char m_a = 'a';
public char A
{
get { return m_a; }
set { m_a = value; }
}
char m_B = 'b';
public char B
{
get { return m_B; }
set{ m_B = value; }
}
char m_c = 'c';
public char C
{
get { return m_c; }
set { m_c = value; }
}
}
}