强迫被叫比预期更晚

时间:2014-02-13 19:16:08

标签: wpf binding coerce

为什么当我在文本框中输入文本时,在调用 MainWindow.Float.Set后,Coerce函数被称为

输入文字后,我原以为:

OnValueCoerce - > OnValueChanged - > MainWindow.Float.Set

但我明白了:

MainWindow.Float.Set - > OnValueCoerce - > OnValueChanged

<Window x:Class="WpfApplication10.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:l="clr-namespace:WpfApplication10"
        Title="MainWindow" Height="350" Width="525">
    <l:TextBoxEx Value="{Binding Float, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</Window>

...

namespace WpfApplication10
{
    public class TextBoxEx : TextBox
    {
        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double), typeof(TextBoxEx), 
            new UIPropertyMetadata(double.NaN, OnValueChanged, OnValueCoerce));

        static object OnValueCoerce(DependencyObject _dep, object _value)
        {
            return _value;
        }

        static void OnValueChanged(DependencyObject _obj, DependencyPropertyChangedEventArgs _arg)
        {
            int gotHere = 6;
        }

        public TextBoxEx()
        {
            var binding = new Binding("Value")
            {
                Source = this,
                UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
                Mode = BindingMode.TwoWay
            };

            SetBinding(TextBox.TextProperty, binding);
        }
    }

    public partial class MainWindow : Window
    {
        float m_float = 7.812345678f;
        public float Float
        {
            get { return m_float; }
            set { m_float = value; }
        }

        public MainWindow()
        {
            DataContext = this;
            InitializeComponent();
        }
    }
}

1 个答案:

答案 0 :(得分:0)

修改

这是绑定的方式。假设您有2个属性A和B.如果A绑定到B,则A的值将首先更新。所以你完全正确地说“价值被写入Float而不经过”价值“的强制功能。

在你的例子中,binding = Value:

SetBinding(TextBox.TextProperty, binding);

在我们的示例中,Value是属性A,并且是TextBox.Text的辅助属性。因此,A(值)将在双向绑定模式中的值B之前更新。

在xaml中,“Value”现在是属性B而Float是属性A,因为Float绑定到Value。

<l:TextBoxEx Value="{Binding Float, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

因此,在更新值之前将更新Float。尝试在xaml或后面的代码中切换Value和Float之间的绑定。

试着这说明我想说的话:

  • 构造函数中的某个地方:

    this.SetBinding(myControl.TesterappProperty, new Binding("TesterApp2") { Source=this,Mode=BindingMode.TwoWay});
    Testerapp = "hello";
    
    this.SetBinding(myControl.TesterApp2Property, new Binding("Testerapp") { Source=this,Mode=BindingMode.TwoWay});
    Testerapp = "hello2";
    
  • ,2个属性如下所示:

    public string Testerapp
    {
        get { return (string)GetValue(TesterappProperty); }
        set { SetValue(TesterappProperty, value); }
    }
    
    //Register Dependency Testerapp Property
    public static readonly DependencyProperty TesterappProperty = 
        DependencyProperty.Register("Testerapp", typeof(string), typeof(myControl), new PropertyMetadata("myDefault", OnTesterappPropertyChanged,mycoerce));
    
    private static object mycoerce(DependencyObject d, object baseValue)
    {
        G2ListBox obj = d as myControl;
        if(obj!= null)
        {
            string s = obj.Testerapp;
        }
        return baseValue;
    }
    
    //Register Dependency TesterApp2 Property
    public static readonly DependencyProperty TesterApp2Property = 
        DependencyProperty.Register("TesterApp2", typeof(string), typeof(myControl), new PropertyMetadata("myDefault2", OnTesterApp2PropertyChanged, mycoerce2));
    
    private static object mycoerce2(DependencyObject d, object baseValue)
    {
        G2ListBox obj = d as myControl;
        if (obj != null)
        {
            string s = obj.Testerapp;
        }
        return baseValue;
    }
    

在每个胁迫方法中设置一个断点,并查看每次首先击中哪一个。这可能解释了我想说的更好一点。

再一次 - 我不确定为什么会这样做,但我之前遇到了类似的问题并通过创建另一个属性(在你的案例中 - 外部值属性)来解决它。你拥有的value属性被绑定到Textbox并变为私有;而外部属性在xaml中就已经有了限制。我猜你也可能只订阅Textbox.PropertyChanged事件而不是创建2个属性。然后通过事件处理来强制执行。

然而,这只是一些解决方案,我知道它并没有完全解释你为什么会发生这样的问题。我想要做绑定你需要一个重要的层次结构(应该首先更新哪个属性值),这就是MS决定这样做的方式。
我的第一个想法是期望一个逻辑流(即如果Textbox值改变然后值改变然后Float改变,同样如果Float =&gt; value =&gt; textbox),但它似乎不是这是绑定背后的真正机制。
现在,它的实现方式实际上可能更好,因为现在您可以选择首先需要更新哪个属性值。