WPF Sentinel对象以及如何检查内部类型

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

在现有代码中,这可能导致虚假exception,其中代码没有准备好。 这些可以被数据绑定子系统吞噬,或者它们可能造成严重破坏。 密切关注您的调试控制台。

无论如何,我在这个MSDN论坛上了解到了这一点 。 Sam Bent的post解释了这一切 。 现在去看看, 你会想知道这一点 。 本质上是这些事件永远不会被解雇(这就是错误),所以:

如果DataContext是sentinel对象,则忽略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类型精确检查类型,而无需求助于字符串比较?

这个?

 var disconnectedItem = typeof(System.Windows.Data.BindingExpressionBase) .GetField("DisconnectedItem", BindingFlags.Static | BindingFlags.NonPublic) .GetValue(null); 

在.NET 4.5中,您现在可以与BindingOperations.DisconnectedSource进行比较。