为什么当我在文本框中输入文本时,在调用 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();
}
}
}
答案 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),但它似乎不是这是绑定背后的真正机制。
现在,它的实现方式实际上可能更好,因为现在您可以选择首先需要更新哪个属性值。