Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF Sentinel objects and how to check for an internal type

As some of you have discovered, a new feature (?) appeared WPF 4, where the data binding engine may pass your custom control instances of the class MS.Internal.NamedObject with the name "{DisconnectedItem}" into the DataContext - instead of the data item your code is expecting (this happens when a templated control is disconnected by its ItemsControl). These are called sentinel objects.

In existing code, this can lead to spurious exceptions where the code is unprepared for it. These can be swallowed up by the data binding subsystem, or they can wreak havoc. Keep an eye on your debug console.

Anyway, I learned about this on this MSDN forum. And there's a post by Sam Bent which explains it all. Go read it now, you'll want to know this. The essence is that these events should never have fired (that's the bug), so:

Ignore the DataContextChanged event if the DataContext is a sentinel object.

So, so I want to check my DataContext. But how? Consider:

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

Guess what happens? It doesn't compile because MS.Internal.NamedObject is internal, and not accessible to me. Of course, I can hack it like this:

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

(or something, which works). I have also followed Sam's suggestion to cache the object for later reference equality checks (it's a singleton).

Of course, this means I don't have a problem, not really. But I'm curious, and this posting will be sure to benefit some users, so it's worth asking anyway:

Is there a way I can exactly check the type against the internal NamedObject type, without resorting to string comparisons?

like image 331
Tor Haugen Avatar asked Oct 06 '10 00:10

Tor Haugen


2 Answers

In .NET 4.5, you can now compare against BindingOperations.DisconnectedSource.

like image 103
Charlie Avatar answered Nov 06 '22 09:11

Charlie


This one?

var disconnectedItem = typeof(System.Windows.Data.BindingExpressionBase)
    .GetField("DisconnectedItem", BindingFlags.Static | BindingFlags.NonPublic)
    .GetValue(null);
like image 16
dtb Avatar answered Nov 06 '22 10:11

dtb