0

为什么当我在文本框中输入文本时,在调用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();
        }
    }
}
4

1 回答 1

0

编辑

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

在您的示例中,绑定=值:

SetBinding(TextBox.TextProperty, binding);

在我们的示例中,值是属性 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 => value => textbox),但这似乎不是绑定背后的真正机制。
然而,现在完成的方式实际上可能会更好,因为现在您可以选择首先需要更新的属性值。

于 2014-02-13T23:32:16.557 回答