31

正如你们中的一些人所发现的那样,WPF 4 出现了一个新功能 (?),其中数据绑定引擎可以将您的自定义控件实例传递给名为“ {DisconnectedItem} ”的类MS.Internal.NamedObject到 DataContext - 而不是您的代码所期望的数据项(当模板化控件被其 ItemsControl 断开连接时会发生这种情况)。这些被称为哨兵对象。

在现有代码中,这可能会导致代码没有为此做好准备的虚假异常。这些可能会被数据绑定子系统吞噬,也可能造成严重破坏。密切关注您的调试控制台。

无论如何,我在这个 MSDN 论坛上了解到了这一点。Sam Bent 的一篇文章解释了这一切。现在去读吧,你会想知道的。本质是这些事件不应该被触发(这就是错误),所以:

如果 DataContext 是哨兵对象,则忽略 DataContextChanged 事件。

所以,所以我想检查我的 DataContext。但是怎么做?考虑:

public bool IsSentinelObject(object dataContext)
{
    return (dataContext is MS.Internal.NamedObject);
}

猜猜会发生什么?它无法编译,因为 MS.Internal.NamedObject 是内部的,我无法访问。当然,我可以像这样破解它:

public bool IsSentinelObject(object dataContext)
{
    return dataContext.GetType().FullName == "MS.Internal.NamedObject"
           || dataContext.ToString() == "{DisconnectedObject}";
}

(或其他有效的东西)。我还按照 Sam 的建议缓存对象以供以后进行引用相等检查(它是单例)。

当然,这意味着我没有问题,不是真的。但是我很好奇,而且这个帖子肯定会让一些用户受益,所以无论如何都值得一问:

有没有一种方法可以准确地检查内部 NamedObject 类型的类型,而无需进行字符串比较?

4

2 回答 2

28

在 .NET 4.5 中,您现在可以与BindingOperations.DisconnectedSource.

于 2014-06-05T20:42:58.223 回答
16

This one?

var disconnectedItem = typeof(System.Windows.Data.BindingExpressionBase)
    .GetField("DisconnectedItem", BindingFlags.Static | BindingFlags.NonPublic)
    .GetValue(null);
于 2010-10-06T00:55:32.043 回答