(edit : correction following Nick's comment, about which thread actually creates the elements)
This exception is confusing for multiple reasons: the code causing it does works on some occasions, the storyboard(s) referencing the infringing name are valid, an element does exist with the name, and has been declared prior to its reference in the storyboard(s) in XAML. This post describes one of the cause for this exception:
Below is a XAML snippet demonstrating the issue (available in the project accompanying this article)
At first glance, everything should work:
- The button is created and added to the GroupBox
- The Click event is fired on the button
- which in turns triggers the EventTrigger which will animation the myRectangle element of the button's ControlTemplate
Unfortunately, running the program will cause an InvalidOperationException. The reason? The threads responsible for WPF's layout. As opposed to Windows Forms -which is completely single threaded- the WPF runtime does not wait until everything is created and rendered to give back control to the UI thread. In this example, and as Nick Kramer explains in his post, the UI thread queues messages that will be handled by the very same thread, but at a later time (during the layout pass). In our case, the ControlTemplate's myRectangle element has not yet been created when the storyboard tries to reference it, thus causing the exception. As a side note, no exception is thrown when changing the button's parent, as it does not cause a complete re-creation of the control.
As of 3.5 SP1, there is unfortunately no way to determine exactly when an element has been created by the rendering thread. The workaround I use is quite simple, queue the RaiseEvent call to the Dispatcher thread with a (very) low priority.
Another workaround, provided by Nick himself (thanks!), is to call UpdateLayout() prior to raising the event.