views:

54

answers:

1

Hi folks,

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?

+2  A: 

This one?

var disconnectedItem = typeof(System.Windows.Data.BindingExpressionBase)
    .GetField("DisconnectedItem", BindingFlags.Static | BindingFlags.NonPublic)
    .GetValue(null);
dtb
That's very nice! :-)
Tor Haugen
Out of curiosity, how did you find that static field? I'd never think to look at BindingExpressionBase.
Tor Haugen
@Tor Haugen: It actually took several attempts, but in the end I did a simple full text search on the [entire .NET 4 source code](http://referencesource.microsoft.com/netframework.aspx). :-)
dtb
Although not excactly the answer I was looking for (how to check if an object is of some inaccessible type), I have accepted this one because it's neat, and perfect for retrieving an instance to check for reference equality to. Thanks.
Tor Haugen
Still, non-public stuff is not to be relied on. What if MS decides to change the name? Code will start to break.
Peter Lillevold