bto.rdz
bto.rdz

Reputation: 6720

Multiple instances dependency property

So I am getting a behavior I don't like and I don't see how to solve it, let's say I have a simple user control with a DependencyProperty as follows:

public static readonly DependencyProperty CollectionProperty =
    DependencyProperty.Register(
        "Collection", 
        typeof (ObservableCollection<string>), 
        typeof (TestControl),
        new PropertyMetadata(new ObservableCollection<string>())); 

public ObservableCollection<string> Collection
{
    get { return (ObservableCollection<string>) GetValue(CollectionProperty); }
    set { SetValue(CollectionProperty, value); }
}

Then I created 2 diferent instances of this control, notice That I added "Hello" in one control and "World" in the second one, the user control only contains a ItemsControl showing the DependencyProperty we created.

<chartsTest:TestControl Background="Red">
    <chartsTest:TestControl.Collection>
        <system:String>hello</system:String>
    </chartsTest:TestControl.Collection>
</chartsTest:TestControl>
<chartsTest:TestControl Background="Blue">
    <chartsTest:TestControl.Collection>
        <system:String>World</system:String>
    </chartsTest:TestControl.Collection>
</chartsTest:TestControl>

And I get "Hello World" in both controls:

enter image description here

I think I understand that this happens because the defualt collection is being initialized as a static variable, ok but then how do I initialize it for each instance?

I know that if I use this sintax it will work:

<chartsTest:TestControl Background="Blue" x:Name="TestControl" 
                        Collection="{Binding Path=TestProperty}">                
</chartsTest:TestControl>

Is there any way to make both work? I hope I am clear enough, this is a simple example tryin to represent my problem.

Upvotes: 2

Views: 1029

Answers (2)

tgpdyk
tgpdyk

Reputation: 1233

Remember that any DP should be declared as static so the value should be initialized.

On the constructor of your UserControl (TestControl), initialize your Collection property:

Update:

SetCurrentValue(CollectionProperty, new List<string>());

We can test it by:

<local:TestControl Background="Red">
   <local:TestControl.Collection>
          <system:String>hello</system:String>
    </local:TestControl.Collection>
</local:TestControl>

<local:TestControl Background="Blue">
     <system:String>world</system:String>
</local:TestControl>

<local:TestControl Background="Green" Collection="{Binding List}"/>

By the way if you are not listening with item change of your list, I suggest to use a List instead.

Upvotes: 2

Mark Feldman
Mark Feldman

Reputation: 16119

This behaviour is by design, you're not explicitly creating an ObservableCollection so the dependency properties all share the default one you're creating when you register it. There are several ways to solve this but probably the easiest is to to set the default to null and create a wrapper class for ObservableCollection:

public class StringObservableCollection : ObservableCollection<string>
{
}

Then use this in your XAML to wrap your list elements:

    <chartsTest:TestControl Background="Red">
        <chartsTest:TestControl.Collection>
            <local:StringObservableCollection>
                <system:String>hello</system:String>
            </local:StringObservableCollection>
        </chartsTest:TestControl.Collection>
    </chartsTest:TestControl>
    <chartsTest:TestControl Background="Blue">
        <chartsTest:TestControl.Collection>
            <local:StringObservableCollection>                  
                <system:String>World</system:String>
            </local:StringObservableCollection>
        </chartsTest:TestControl.Collection>
    </chartsTest:TestControl>

Alternatively you can set the value in the constructor as tgpdyk has already pointed out. More details here.

Upvotes: 1

Related Questions