2

我不确定这是否是4.0我对 DP 和绑定的错误或误解。*注意:这适用于 3.5 和 4.5...只是不适用于 4.0

考虑以下代码:

虚拟机:

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 本身做了 a target.SetValue(dp, bindingExpressionBase);,这解释了为什么它一次可以工作。

4

1 回答 1

0

这当然看起来很奇怪,但我认为这里发生的事情与绑定的源无关,而是你如何设置路径。您的第一个案例调用SetBinding(DependencyProperty, string),而后者又调用SetBinding(DependencyProperty, new Binding(path))Binding构造函数在内部将其设置为Path-new PropertyPath(path, new object[0])没有参数的路径。

在第二种情况下,您正在创建自己的PropertyPath,但是通过一个不同的构造函数,该构造函数接受一个 typeobject的参数,它表示一个参数。该构造函数似乎设置Path"(0)"并将您的"MyProp"字符串设置为绑定的参数。

以下是 MSDN 关于该构造函数的说明:

此构造函数有两种完全不同的用法,具体取决于它是用于绑定的源模式属性路径,还是用于情节提要目标的目标模式单步属性路径。

如果在源模式下将此 PropertyPath 用于绑定,则参数是表示属性名称的字符串,或者可以是描述正在用作对象的 CLR 对象模型中的属性的“逐步”路径的字符串绑定的来源。对于绑定属性路径,标识“步骤”的字符是点 (.)。还支持索引器引用(包括多个索引器和类型区分)。有关 Binding 对象专门使用的字符串语法的更多详细信息,请参阅 Binding.Path。用作绑定源的属性不必是依赖属性。如果绑定双向更新,则引用的属性必须是可读写的。另请注意,绑定目标必须是依赖属性。有关详细信息,请参阅数据绑定概述。

如果在目标模式下将此 PropertyPath 用于情节提要目标的单步路径,则参数通常作为 DependencyProperty 类型提供。您还可以指定一个字符串,即名称。这些中的任何一个都评估为相同的结果,因为它在内部存储为字符串。提供的 DependencyProperty 通过 DependencyPropertyConverter 转换为字符串。DependencyPropertyConverter 支持依赖属性的限定命名格式,因此您可以在代码中为 PropertyPath.PropertyPath 构造函数指定 typeName.propertyName 限定依赖属性名称字符串。依赖属性标识符的限定路径与复杂路径是不同的概念。应改为使用 PropertyPath.PropertyPath 构造函数创建复杂路径 PropertyPath。

我仍然不确定为什么你的第一个案例不起作用,但想象一下,由于某种原因,因为参数不必依赖属性,但可以是常规 CLR 属性,它被视为后者。

在第二种情况下,该属性被解释为“情节提要目标的单步路径”(尽管我想它可能不是),但由于在这种用法中它必须是依赖属性,因此绑定处理它的方式不同。

为了保持一致性,您可以尝试在第二种情况下将 Path 设置为:

Path = new PropertyPath("MyProp", new object[0])

当然,现在我希望您的绑定在这两种情况下都只能工作一次!它可能会恢复一些理智,但也可能表明绑定问题存在于其他地方。

于 2013-04-04T01:58:13.033 回答