I'm trying to create a dynamic expandable toolbox, like shown on the picture below.
The custom control will put the different items in the base and advanced menus depending on the available space. If there's enough space to display all the items in the base menu, then the advanced menu won't be displayed. I have created this control, and it works as long as I use it only once in an application. If I instanciate it multiple times I get the exception below, which I'm having a hard time trying to understand, given that I'm just adding an element into a non static list.
Would anybody have another idea on how to create this control differently to avoid this problem, or knows what creates this exception?
Link to the solution : ButtonsItemsControl (To reproduce the problem just uncomment line 15 of MainWindow.xaml
Any help appreciated
Your problem lies in the declaration of dependency properties of your ButtonsItemsControl
class:
public ObservableCollection<FrameworkElement> BasedMenuItems
{
get { return (ObservableCollection<FrameworkElement>)GetValue(BasedMenuItemsProperty); }
set { SetValue(BasedMenuItemsProperty, value); }
}
public static readonly DependencyProperty BasedMenuItemsProperty =
DependencyProperty.Register("BasedMenuItems", typeof(ObservableCollection<FrameworkElement>), typeof(ButtonsItemsControl),
new PropertyMetadata(new ObservableCollection<FrameworkElement>()));
You set a default value to that dependency property, which is an instance of ObservableCollection<FrameworkElement>
. The problem is, this instance is created when this line is executed, which is when your class is loaded in memory and static fields are initialized. So that means that every instance of ButtonsItemsControl
will share the same collection object if those properties are not overwritten.
You should remove the default value in the PropertyMetadata
constructor, and instead set a new value when your control is instantiated, in its own constructor:
public ButtonsItemsControl()
{
BasedMenuItems = new ObservableCollection<FrameworkElement>();
...
}
It seems counter-intuitive, but to my knowledge there is no better way (actually the framework uses factory objects internally which create new instances of classes to produce unique default values, but for whatever reason they didn't expose those factories outside the framework).