c# - Objetos WPF Sentinel y cómo buscar un tipo interno
.net data-binding (2)
Como algunos de ustedes han descubierto, apareció una nueva característica (?) WPF 4, donde el motor de enlace de datos puede pasar sus instancias de control personalizadas de la clase MS.Internal.NamedObject con el nombre " {DisconnectedItem} " en el DataContext, en lugar de el elemento de datos que espera su código (esto ocurre cuando un Control de plantilla está desconectado por su Control de elementos). Estos se llaman objetos centinelas.
En el código existente, esto puede conducir a excepciones falsas en las que el código no está preparado para ello. Estos pueden ser absorbidos por el subsistema de enlace de datos o pueden causar estragos. Vigila tu consola de depuración.
De todos modos, aprendí sobre esto en este foro de MSDN . Y hay una publicación de Sam Bent que lo explica todo . Ve a leer ahora, querrás saber esto . La esencia es que estos eventos nunca deberían haberse disparado (ese es el error), entonces:
Ignore el evento DataContextChanged si DataContext es un objeto centinela.
Entonces, quiero verificar mi DataContext. ¿Pero cómo? Considerar:
public bool IsSentinelObject(object dataContext)
{
return (dataContext is MS.Internal.NamedObject);
}
Adivina que pasa? No se compila porque MS.Internal.NamedObject es interno y no es accesible para mí. Por supuesto, puedo hackearlo así:
public bool IsSentinelObject(object dataContext)
{
return dataContext.GetType().FullName == "MS.Internal.NamedObject"
|| dataContext.ToString() == "{DisconnectedObject}";
}
(o algo, que funciona). También he seguido la sugerencia de Sam de almacenar en caché el objeto para posteriores controles de igualdad de referencia (es un singleton).
Por supuesto, esto significa que no tengo un problema, realmente no. Pero tengo curiosidad, y esta publicación seguramente beneficiará a algunos usuarios, por lo que vale la pena preguntar de todos modos:
¿Hay alguna forma de que pueda verificar exactamente el tipo contra el tipo interno de NamedObject, sin recurrir a comparaciones de cadenas?
¿Éste?
var disconnectedItem = typeof(System.Windows.Data.BindingExpressionBase)
.GetField("DisconnectedItem", BindingFlags.Static | BindingFlags.NonPublic)
.GetValue(null);
En .NET 4.5, ahora puede comparar contra BindingOperations.DisconnectedSource
.