31

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?

Azhar
  • 20,500
  • 38
  • 146
  • 211
Tor Haugen
  • 19,509
  • 9
  • 45
  • 63
  • `DataContextChanged` [is no longer raised in in .NET 4.5. when {DisconnectedObject} would be passed.](https://connect.microsoft.com/VisualStudio/feedback/details/619658/wpf-virtualized-control-disconnecteditem-reference-when-datacontext-switch). – Steven Jeuris Mar 18 '15 at 11:21
  • I still encounter similar problems in .NET 4.5 while binding `DataContext` to an inner element of the DataContext (view model composition). The workaround was to simply prevent from doing this and rather updating all binding paths to `InnerElement.[whathever]`. – Steven Jeuris Mar 18 '15 at 15:46

2 Answers2

30

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

Charlie
  • 15,069
  • 3
  • 64
  • 70
16

This one?

var disconnectedItem = typeof(System.Windows.Data.BindingExpressionBase)
    .GetField("DisconnectedItem", BindingFlags.Static | BindingFlags.NonPublic)
    .GetValue(null);
dtb
  • 213,145
  • 36
  • 401
  • 431
  • Out of curiosity, how did you find that static field? I'd never think to look at BindingExpressionBase. – Tor Haugen Oct 06 '10 at 19:23
  • @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 Oct 06 '10 at 19:27
  • 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 Oct 10 '10 at 23:37
  • 4
    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 Oct 14 '10 at 13:52
  • @PeterLillevold This code in particular, so finding the source would be rather trivial. (Although it would be best to add a null check to verify whether the `disconnectedItem` is found, throwing an exception if it isn't.) – Steven Jeuris Mar 18 '15 at 11:17