WPF UserControl List

Started by
6 comments, last by Tasaq 10 years, 4 months ago

Hi,

this is going to be quick question. I want to create a user control that would do something like this:


<ctrl:MyControl x:Name="mc">
    <ctrl:MyControl.MyData>
        <ctrl:MyDataCollection>
            <ctrl:MyData MyProperty="{Binding PropertyA}"/>
            <ctrl:MyData MyProperty="{Binding PropertyB}"/>
        </ctrl:MyDataCollection>
    </ctrl:MyControl.MyData>
</ctrl:MyControl>

MyControl is UserControl,

MyControl.MyData is DependencyProperty of type MyDataCollecion inside MyControl,

MyDataCollecion is List<MyData>,

MyData is DependencyObject, MyProperty is dependency property

Is such thing possible in WPF?

I Believe that it would lose connection to logical tree in MyData, so the result would be MyData added to MyDataCollection, but MyProperty wouldn't be bound.

Any ideas how I can achieve something like that?

Advertisement

Yes, this is possible.

You don't lose the bindings, if MyData::MyProperty is indeed a dependency property.

I assume that MyDataCollection is a descendant of the Collection<T> class? If this is the case, then your code should work as is.

On the code-behind of the MyControl, be sure to initialize the collection to an unique new instance in a non-static (public or private) constructor. The dependency property registration mechanism causes initial object instances to be static, so if you don't create a new instance in the instance constructor, the default static collection instance gets shared among all the instances of the class to which the property gets registered.

Niko Suni

It doesn't work. I have MVVM with INotifyPropertyChanged, and when I change the PropertyA I don't even recieve callback from MyProperty. I tried to initialize Collection
in MyControl constructor but no luck.

I also get this error in output:


System.Windows.Data Error: 2 :
Cannot find governing FrameworkElement or FrameworkContentElement for target element.
BindingExpression:Path=PropertyA;
DataItem=null;
target element is 'MyData' (HashCode=60484054);
target property is 'MyProperty' (type 'Double')

The usual case is that you have a viewmodel class that holds the collections you want to bind for a view. Is MyControl derived from UserControl? If that is the case, you are mixing MVVM responsibilities.

If you have controls in your MyControl children, and you want to bind them to the properties of the control itself, you can use the RelativeSource property of the binding and set it to "self" or the parent control (and the path to the collection as appropriate).

Niko Suni

One possible catch of the property change callback system is that if the computed value of the binding happens to be the same as the previous value (remember that null == null), the callback does not get called.

Niko Suni

The usual case is that you have a viewmodel class that holds the collections you want to bind for a view. Is MyControl derived from UserControl? If that is the case, you are mixing MVVM responsibilities.

If you have controls in your MyControl children, and you want to bind them to the properties of the control itself, you can use the RelativeSource property of the binding and set it to "self" or the parent control (and the path to the collection as appropriate).


Yes, MyControl is derived from UserControl. I want to use MyControl to visualise my data (I assign instance of class that's the holder of PropertyA and PropertyB to DataContext of MyControl).

I don't have controls in MyControl.

Here is similar problem, MyData deriving FrameworkElement get rid of the error I pasted above, but still no luck in binding.

EDIT:

Almost there :)


<UserControl.Resources>
        <cnv:MyObject x:Key="MyObject"/>
</UserControl.Resources>

<ctrl:MyControl x:Name="mc">
    <ctrl:MyControl.MyData>
        <ctrl:MyDataCollection>
            <ctrl:MyData MyProperty="{Binding PropertyA}"/>
            <ctrl:MyData MyProperty="{Binding Source={StaticResource MyObject}, Path=PropertyB}"/>
        </ctrl:MyDataCollection>
    </ctrl:MyControl.MyData>
</ctrl:MyControl>

It almost works, now I can see that value changed in MyControl, but... it doesn't detect that I change value of PropertyB, it always got default value from MyObject constructor.

Does MyObject implement property change notification (via INotifyPropertyChanged) -or- is PropertyB a dependency property?

Niko Suni

Does MyObject implement property change notification (via INotifyPropertyChanged) -or- is PropertyB a dependency property?

MyObject impelements INotifyPropertyChanged. PropertyB is regular property (set has NotifyPropertyChanged).

I wrote the code described above and put it here. This should make it easier to find what I am doing wrong :) .

This topic is closed to new replies.

Advertisement