我不确定这是4.0
中的错误还是对我的DP和绑定的误解。
*注意:这适用于3.5和4.5 ......不是4.0
请考虑以下代码:
VM:
public MyEnum MyProp
{
get{return _myProp;}
set
{
_myProp = value;
OnPropertyChanged("MyProp");
}
}
查看(依赖属性设置):
MyDP= DependencyProperty.Register("MyProp", typeof(MyEnum), typeof(MyControl), new PropertyMetadata(DefaultEnumVal, MyPropChanged));
查看(在datacontextchanged事件中):
第一个选项
this.SetBinding(MyDP, "MyProp"); //Only triggers MyPropChanged once
第二个选项
this.SetBinding(MyDP,
new Binding
{
Source=this.DataContext,
Path = new PropertyPath("MyProp")
}
); //Works as expected
所以,鉴于所有这些,为什么第一个选项只触发属性更改一次,并且更详细的方法继续超出第一个更改?我认为第一个/字符串版本固有地使用了this.DataContext
?如果我安装了.NET 4.5
,那么这可以正常运行,这让我相信这是一个4.0错误,可能与在DataContextChanged
事件中执行此操作有关吗?
但是,也许我错过了一些东西,所以这就是我在这里问的原因:)
更新
默认情况下,绑定会继承由...指定的数据上下文 DataContext属性,如果已设置
而且,每次反思:
public BindingExpression SetBinding(DependencyProperty dp, string path)
{
return (BindingExpression)this.SetBinding(dp, new Binding(path));
}
所以,所有这一切都是调用与上面相同的代码,只是没有设置源代码。这应该会导致更新针对DataContext
如果我将Source
null
留在第二个选项中,我可以重现第一个选项
更新#2
显然在4.5中,他们添加了ResolvedSource
属性。这表明在4.5中,源代码可以解析为我所期望的。我将其追溯到ClrWorker
,发现SourceItem
确实正在被正确评估...至少在SetBinding
时。我将看看是否有办法让我跟踪这一点,看看它是否/何时发生变化。
更新#3
经过进一步调试后,我发现更改的事件仅发生在SetBinding
上。如果我将DefaultEnumValue
设置为SetBinding
出现时的状态,则根本不会触发更改
更新#4
如果我拨打this.SetValue(MyDP, SomeEnumVal);
*,那么这可以工作甚至写入VM。我已经尝试更改DP,以便将元数据设置为twowaybindingbydefault以查看是否有帮助,但它没有
*这并不让我感到惊讶,因为SetBinding本身会执行target.SetValue(dp, bindingExpressionBase);
,这就解释了为什么它可以运行一次。
答案 0 :(得分:0)
这看起来确实很奇怪,但我认为这里发生的事情与Binding的Source无关,而是你如何设置Path。您的第一个案例会调用SetBinding(DependencyProperty, string)
,然后调用SetBinding(DependencyProperty, new Binding(path))
。 Binding
构造函数在内部将Path
设置为new PropertyPath(path, new object[0])
- 没有参数的路径。
在第二种情况下,您正在创建自己的PropertyPath
,但是通过一个不同的构造函数,它接受一个类型object
的参数,它表示一个参数。该构造函数似乎将Path
设置为"(0)"
并将您的"MyProp"
字符串设置为绑定的参数。
以下是MSDN对该构造函数的说法:
这个构造函数有两个完全不同的用法取决于 是否用于a的源模式属性路径 绑定,或用于a的目标模式单步属性路径 故事板目标。
如果在源模式下使用此PropertyPath进行绑定,则参数为 表示属性名称的字符串,或者可以是字符串 描述了CLR对象中属性的“逐步”路径 正在用作绑定源的对象的模型。 对于绑定属性路径,标识“步骤”的字符是 一个点(。)。索引器引用(包括多个索引器和类型 差异化)也得到支持。有关语法的更多详细信息 Binding对象专门使用的字符串,请参阅 Binding.Path。用作绑定源的属性不必是a 依赖属性。如果绑定更新双向,则属性 引用必须是读写。另请注意绑定目标 必须是一个依赖属性。有关详细信息,请参阅数据绑定 概述
如果在目标模式下使用此PropertyPath作为a的单步路径 故事板目标,参数通常作为类型提供 的DependencyProperty。您还可以指定名称的字符串。 这些中的任何一个都会评估相同的结果,因为它是存储的 内部作为字符串。提供的DependencyProperty将转换为 通过DependencyPropertyConverter的字符串。该 DependencyPropertyConverter支持合格的命名格式 依赖项属性,因此您可以指定typeName.propertyName 限定的依赖属性名称字符串 代码中的PropertyPath.PropertyPath构造函数。合格的路径 依赖属性标识符是一个不同的概念 复杂的道路。应该创建一个复杂路径的PropertyPath 使用PropertyPath.PropertyPath构造函数。
我仍然不确定为什么你的第一个案例不起作用,但想象一下,由于某些原因,因为参数不 是一个依赖属性,但可以是一个普通的CLR财产,被视为后者。
在第二种情况下,该属性被解释为“故事板目标的单步路径”(即使我想象它可能不是),但由于在这种用法中它必须一个依赖属性,绑定以不同的方式处理它。
为了保持一致性,您可以尝试在第二种情况下将Path设置为:
Path = new PropertyPath("MyProp", new object[0])
当然,现在我希望你的绑定在两种情况下都只能工作一次!它可能会恢复一些理智,但也可能表明绑定问题存在于其他地方。