Wednesday, January 4, 2012

"Value does not fall within the expected range." When Adding a Control in Code

"Value does not fall within the expected range" is an error I expect to receive when attempting to access an element of an Array that does not exist.  Unfortunately, I have spent the last day receiving this message intermittently when trying to perform an Add on a UIElement's Children in Silverlight.

If you're like me, you received this error and immediately started Googling how to fix it by typing in the error and adding things like "Add" and "Silverlight."  If you do this, you'll find a few results - almost exclusively about namescope conflicts.  Well, there's a reason - that really is the problem no matter what all of your other investigations point towards.

Here were my exact symptoms: I was adding a context menu to a Grid dynamically.  When the Grid initially loaded, the context menu was added.  It was performed this way so that we could have a generic GridBehavior that included the ContextMenu instead of having a hard coded ContextMenu on each of our Grids.  However, this code worked fine for years - why did it suddenly break?

Well, what changed?  We had recently performed a merge, and this is when the problem started occurring.  So, easy enough - I rolled back all of the GridBehavior changes (this is where the error was actually occurring after all), as well as any other file that seemed to be impacted by the GridBehavior changes (those that didn't build correctly after I rolled the first file back).  This would fix it if it were merge related right?  Well, no luck - it still failed.

What else can I try?  Well, everything told me that it was about namescope conflicts.  So, right before I added the control, I appended a random modifier to the Name - this should fix it, right?  No luck.

What if I check for the Name to be used in the namescope of the parent I was adding it to?  Or even the Application's RootVisual?  Well - I told you that this error was occurring intermittently, and none of these checks coincided with whether the error would occur or not - they would always be either true or false, but not change based on whether the code blew up.

Then I noticed something - this control had a name.  And it received that name in the XAML.  I started thinking about this for a bit, and I wondered how long it had had that name.  Checking the history - it received it in that last merge!  Therefore, I ripped that name out and started testing again.  Lo and behold, everything worked!

Here's the moral of this story: that error message really is about a namescope conflict.  Believe it!  It's somewhere in there!  Secondly - don't name things in XAML that don't need names - especially don't do this if you're later going to add them dynamically - you can't guarantee that you'll only add it once instead of multiple times in the namescope!