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

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

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

Во всяком случае, я узнал об этом на этот форум MSDN. И есть сообщение Сэма Бента, в котором 4309-a793-4001488b23aa" rel="noreferrer">все это объясняет. Прочитайте это сейчас, вы захотите это узнать. Суть в том, что эти события никогда не должны были срабатывать (это баг), поэтому:

Игнорируйте событие 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, не прибегая к сравнению строк?


person Tor Haugen    schedule 06.10.2010    source источник
comment
DataContextChanged больше не вырос в .NET 4.5. когда будет передан {DisconnectedObject}..   -  person Steven Jeuris    schedule 18.03.2015
comment
Я все еще сталкиваюсь с подобными проблемами в .NET 4.5 при привязке DataContext к внутреннему элементу DataContext (композиция модели представления). Обходной путь заключался в том, чтобы просто предотвратить это и обновить все пути привязки до InnerElement.[whathever].   -  person Steven Jeuris    schedule 18.03.2015


Ответы (2)


Этот?

var disconnectedItem = typeof(System.Windows.Data.BindingExpressionBase)
    .GetField("DisconnectedItem", BindingFlags.Static | BindingFlags.NonPublic)
    .GetValue(null);
person dtb    schedule 06.10.2010
comment
Из любопытства, как вы нашли это статическое поле? Я бы никогда не подумал взглянуть на BindingExpressionBase. - person Tor Haugen; 06.10.2010
comment
@Tor Haugen: на самом деле потребовалось несколько попыток, но в конце концов я выполнил простой полнотекстовый поиск по всему Исходный код .NET 4. :-) - person dtb; 06.10.2010
comment
Хотя это не совсем тот ответ, который я искал (как проверить, относится ли объект к какому-то недоступному типу), я принял этот ответ, потому что он аккуратный и идеально подходит для получения экземпляра для проверки на равенство ссылок. Спасибо. - person Tor Haugen; 11.10.2010
comment
Тем не менее, на непубличные вещи нельзя полагаться. Что, если MS решит изменить имя? Код начнет ломаться. - person Peter Lillevold; 14.10.2010
comment
@PeterLillevold В частности, этот код, поэтому найти источник было бы довольно тривиально. (Хотя было бы лучше добавить нулевую проверку, чтобы проверить, найден ли disconnectedItem, выдавая исключение, если это не так.) - person Steven Jeuris; 18.03.2015

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

person Charlie    schedule 05.06.2014