別のプロジェクトで発生している問題を解決しようとすると、問題を再現するために次の例を作成しました。
ユーザーがスライダーまたはテキストボックスを介して新しい値を入力すると、それらの値はコンバーターを介して「ConvertedBack」になり、ソースが更新されるという考え方です。InternalRepのプロパティが書き込まれているが、InternalRepPropertyのbindexpressionに通知していないため、これは表示されていないようです。
この問題を解決するための最善の方法は何ですか?
私が試した1つの方法は、スライダーのValueChangedイベントを処理することでしたが、これにより、コンバーターが... ConvertBack 、 Convert 、 ConvertBack 、 Convertの順になりました。理由はわかりません。
ユーザーが値を変更するとき、ソースを更新するためにConvertBackのみを使用するコンバーターが必要ですが、他には何も必要ありません。これは可能ですか?
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>
メインウィンドウコード
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; }
}
}
}