Объекты WPF Sentinel и как проверить внутренний тип

Как некоторые из вас обнаружили, появилась новая функция (?) WPF 4, в которой механизм привязки данных может передавать ваши пользовательские экземпляры управления класса MS.Internal.NamedObject с именем " {DisconnectedItem}" в DataContext - вместо элемента данных, ожидаемого вашим кодом (это происходит, когда шаблонный элемент управления отключается его ItemsControl). Они называются дозорными объектами.

В существующем коде это может привести к ложным исключениям, когда код для него не готов. Они могут быть проглочены подсистемой привязки данных, или они могут нанести ущерб. Следите за консолью отладки.

В любом случае, я узнал об этом на этом форуме MSDN. И есть сообщение от Сэма Бента, которое объясняет все это. Пойдите, прочитайте это сейчас, вы захотите это узнать. Суть в том, что эти события никогда не должны были срабатывать (что ошибка), поэтому:

Игнорировать событие DataContextChanged, если DataContext - объект-дозор.

Итак, я хочу проверить свой 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}";
}

(или что-то, что работает). Я также следовал предложению Сэма о кешировании объекта для последующих проверок равенства ссылок (это одноэлементный).

Конечно, это означает, что у меня нет проблемы, а не на самом деле. Но мне любопытно, и эта публикация наверняка принесет пользу некоторым пользователям, поэтому стоит все равно спросить:

Есть ли способ, который я могу точно проверить тип в отношении внутреннего типа NamedObject, не прибегая к сопоставлениям строк?

Ответ 1

Этот?

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

Ответ 2

В .NET 4.5 теперь вы можете сравнить с BindingOperations.DisconnectedSource.