Berlo
Berlo

Reputation: 134

Creating a CustomUserControl with a DependencyProperty of type ObservableCollection

I am trying to create a CustomUserControl in WPF. This CustomUserControl contains a DependencyProperty of type ObservableCollection.

My goal is to be able to:

Here is what I have right now:

<my:CustomUserControl ImageList={Binding imgList}/>

ImageList is defined as the following:

public static readonly DependancyProperty ImageListProperty = DependancyProperty.Register
  ("ImageList", typeof(List<ImageSource>), typeof(Switch));

public List<ImageSource> ImageList {
  get { return (List<ImageSource>)GetValue(ImageListProperty); }
  set { SetValue(ImageListProperty, value); }
}

In order to have a new instance of ImageList per CustomUserControl, I have added the following line in the ctor of CustomUserControl:

public CustomUserControl(){
...
SetValue(ImageListProperty, new List<ImageSource>());
}

Now, the following code examples work:

<my:CustomUserControl>
  <my:CustomUserControl.ImageList>
    <BitmapImage UriSource="Bla.png"/>
    <BitmapImage UriSource="Bla2.png"/>
  </my:CustomUserControl.ImageList>
</my:switch>

And this works too:

<my:CustomUserControl ImageList={Binding imgList}/>

But this does not:

<Style TargetType="my:CustomUserControl">
<Setter Property="my:CustomUserControl.ImageList">
        <BitmapImage UriSource="Bla.png"/>
        <BitmapImage UriSource="Bla2.png"/>
</Setter>
</Style>

This leaves all instances with an empty ImageList.

P.S. This is pseudo-code as I don't recall the exact syntax.

Thanks!

Upvotes: 3

Views: 113

Answers (2)

Abe Heidebrecht
Abe Heidebrecht

Reputation: 30498

The reason why you aren't able to set the value in a Style is because you are setting a local value in your constructor. MSDN explains DependencyProperty value precedence in more detail.

Because you just want to give your property a default value per instance, just use SetCurrentValue instead of SetValue in your constructor.

Edit to explain this further

So, a DependencyProperty can be set in multiple ways. It can be set through code, a Binding, a Style, a Trigger, an Animation, or a few other ways. The important thing to know is that there can be multiple attempts to set a given property.

Because of this, WPF has defined a precedence for the values. That means if you set a property in a Style, you can set the property manually to override the Style value. Or a Trigger in the ControlTemplate can override the Style value.

When you set the property in your constructor, you are giving it a local value. From the first link, you will see that only an Animation or Property Coercion can override a local value.

The SetCurrentValue method, however, will allow you to set a value for a property without setting a local value. This is what you need, as you want to be able to set the value in a Style.

Upvotes: 1

kmatyaszek
kmatyaszek

Reputation: 19296

Instead of using List<ImageSource> you should use CompositeCollection (msdn)

public CompositeCollection ImageList
{
    get { return (CompositeCollection)GetValue(ImageListProperty); }
    set { SetValue(ImageListProperty, value); }
}      
public static readonly DependencyProperty ImageListProperty =
    DependencyProperty.Register("ImageList", typeof(CompositeCollection), typeof(CustomUserControl), new PropertyMetadata(new CompositeCollection()));

And now you can set values in the defined style like this:

<my:CustomUserControl x:Name="myCustomUserControl   
    <my:CustomUserControl.Style>
        <Style TargetType="{x:Type my:CustomUserControl}">
            <Setter Property="my:CustomUserControl.ImageList">
                <Setter.Value>
                    <CompositeCollection>
                        <BitmapImage UriSource="Bla.png"/>
                        <BitmapImage UriSource="Bla2.png"/>
                    </CompositeCollection>
                </Setter.Value>
            </Setter>
        </Style>
    </my:CustomUserControl.Style>            
</my:CustomUserControl>

Other binding works in the same way as you presented in your question.

e.g.:

<my:CustomUserControl x:Name="myCustomUserControl">
    <my:CustomUserControl.ImageList>
        <BitmapImage UriSource="Bla.png" />
        <BitmapImage UriSource="Bla2.png" />
    </my:CustomUserControl.ImageList>            
</my:CustomUserControl>

Upvotes: 0

Related Questions