A while ago, we were busy developing custom controls for Silverlight (2 at the time). One of those controls was a Wizard control, which in turn consisted of a list of another custom control, the WizardSlide. Obviously, this list was implemented as a Dependency Property “WizardSlides” (collection of WizardSlide) on the Wizard control.
However, after some testing, I noticed some pretty strange behaviour: everything worked quite fine when only one instance of the Wizard control was used in our application, but from the moment on we started using multiple instances, the WizardSlides-collection property seemed to behave itself as if it were defined on the class instead of on the instance of the class. All of a sudden, we were able to access the combined WizardSlides of instances 1 & 2 through the WizardSlides property on either of the Wizard instances. To make matters even more strange, this didn’t happen if the collection property contained a simple type (like string or int), but it did happen when it contained a UIElement (or derived) type (like the WizardSlide control).
We tried lots of different approaches to solve this problem, searched the internet, posted questions on the Silverlight forum, but to no avail: no-one could explain why this happened nor offer a solution, and we finally opted for a less-than-ideal approach, constricting the number of WizardSlides to 8 instead of having a dynamic collection.
Last week, I was helping out one of our clients with their Silverlight application. An application which uses custom controls. One of which contained a collection that seemed to behave as a singleton instead of on an instance level… I remembered the problems I faced with this before, already thinking we wouldn’t find a solution to keep this collection dynamic. However, I started searching around again, and lo and behold, it wasn’t long before I found this page on MSDN, describing the exact problem we were facing AND offering a reason and solution. I am, by the way, 100% sure this page wasn’t there last year 😉
Apparently, what’s happening is this: when you create a dependency property, it gets its default value through the dependency property metadata you define. If that property is a reference type, this default value isn’t a default value per instance, it is a default value that applies to all instances of the type. This means that when using the collection defined by the collection property metadata (which is singular/static!) as the default value for new instances, your collection dependency property is actually referring to that singular collection, and is thus accessible through any instance of your control!
Interesting, no? 🙂 What’s even more interesting is that there is a very, very easy to solve this: to make sure your collection property isn’t shared between all instances of your control, reset the property value to a unique instance as part of the class constructor call. In the Wizard control with a WizardSlides collection, this looks as such:
public Wizard() : base()
{
//... other constructor tasks
SetValue(WizardSlides, new ObservableCollection<WizardSlide>());
}
Hope this helps some of you out! 🙂