在试图解决我在另一个项目中遇到的问题 - 我创建了以下示例来复制问题。MultiBinding ConvertBack问题
这个想法是,当用户通过滑块或文本框输入新值时,这些值应该通过转换器进行“ConvertedBack”,并更新源代码。虽然我似乎没有看到这一点,但我相信由于InternalRep的属性正在写入,但没有通知InternalRepProperty的bindexpression。
解决此问题的最佳方法是什么?
一种方法我试过是处理ValueChanged事件滑块,但是这引起了对转换器... ConvertBack 然后转换然后 ConvertBack 然后转换,不知道为什么。
当用户改变一个值时,我需要转换器只有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); }
}
}
主窗口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; }
}
}
}
你的'OnSliderChnaged'方法是做什么的?因为你有'TwoWay'绑定,'ConvertBack'将会被调用一次,所以在你的'ValueChanged'事件中第二次调用它将使它运行两次。另外,我仍然试图在后面的代码中找出你的'MultiBinding',但它可能会让它运行两次。 – Rachel
OnSliderChnaged方法没有实现,它只是从一些实验中遗留下来,整个应用程序就像我上面发布的那样。问题是,当用户编辑滑块/文本框时,从不会调用convertback,这正是我试图解决/补救的问题 – wforl
我开始认为存在一个体系结构问题。你试图通过让setter被调用来达到什么目的?为什么当一个滑块绑定到一个变量时会调用所有3个setter?你在计算吗? –