0

currently I am building a custom control with a dependency property. This dependency property should be a list of objects. The problem is, when I declare the dependency property as IEnumerable<> it works and the callback methods gets called. But when I choose an ICollection<> or IList<> the callback method of the dependency property won't get called. The custom control with the dependency property is in a custom control library and is referenced by my current testing project.

Dependency property implementation in my custom control:

private static readonly FrameworkPropertyMetadata depPropMetaData =
    new FrameworkPropertyMetadata(new PropertyChangedCallback(OnStructureChanged));

public static readonly DependencyProperty TreeListStructureProperty =
    DependencyProperty.Register(
        "TreeListStructure",
        typeof(IEnumerable<ITreeListStructure>),
        typeof(TreeListView),
        depPropMetaData);

public IEnumerable<ITreeListStructure> TreeListStructure
{
    get { return (IEnumerable<ITreeListStructure>)this.GetValue(TreeListStructureProperty); }
    set { this.SetValue(TreeListStructureProperty, value); }
}

private static void OnStructureChanged(
    DependencyObject depObj, DependencyPropertyChangedEventArgs eventArgs)
{
    ; //Breakpoint here
}

In my test project with a MainView-window I just bind the DataContext as follows:

TestingWrapperViewModel testingVM = new TestingWrapperViewModel();
testingVM.GenerateTestItems(5);
this.DataContext = testingVM;

For completion the Binding in the MainView.xaml:

<TreeListView:TreeListView TreeListStructure="{Binding ViewModelList}">

The TestingWrapperViewModel-class just contains the following:

class TestingWrapperViewModel : INotifyPropertyChanged
{
    private List<TestingViewModel> _viewModelList = new List<TestingViewModel>();

    public List<TestingViewModel> ViewModelList
    {
        get { return this._viewModelList; }
        set
        {
            this._viewModelList = value;
            OnPropertyChanged("ViewModelList");
        }
    }

    public void GenerateTestItems(uint nAmount)
    {
        //Just generate some objects for testing
    }

    //INotifyPropertyChanged Implemenation
}

The TestingViewModel implements the ITreeListStructure-Interface:

class TestingViewModel : ITreeListStructure, INotifyPropertyChanged

The code I just listed fires the OnStructureChanged event and also returns the specified amount of elements in the DependencyPropertyChangedEventArgs. But when I change the IEnumerable<> in the dependency property declaration to ICollection<> or IList<> or List<> the callback method won't get called at all.

I would like to understand why this won't work. I hope somebody can explain it.

Thanks,

Heenne

EDIT: Bad formating in the comment, added code here:

public void GenerateTestItems(uint nAmount)
    {
        List<TestingViewModel> temp = new List<TestingViewModel>();
        for (uint nCounter = 0; nCounter < nAmount; nCounter++)
        {
            temp.Add(new TestingViewModel("TestObject" + nCounter.ToString()));
        }

        ICollection<ITreeListStructure> test1 = temp; //ERROR
        IEnumerable<ITreeListStructure> test2 = temp;

        this.ViewModelList = temp;
    }

EDIT2: Corrected my EDIT so that the error is visible.

Heenne
  • 88
  • 1
  • 10

1 Answers1

1

The type List<TestingViewModel> is not assignment compatible with ICollection<ITreeListStructure> or IList<ITreeListStructure>:

IEnumerable<ITreeListStructure> x = ViewModelList; // ok
ICollection<ITreeListStructure> y = ViewModelList; // not ok.

This is because IEnumerable<out T> is covariant and ICollection<T> etc. are not.

See this question for details.


In order to access the collection in the dependency property, you should use LINQ:

using System.Linq;
...

private static void OnStructureChanged(
    DependencyObject depObj, DependencyPropertyChangedEventArgs eventArgs)
{
    var tls = (IEnumerable<ITreeListStructure>)eventArgs.NewValue;
    var count = tls.Count();
}
Clemens
  • 123,504
  • 12
  • 155
  • 268
  • Thanks for your response, but I got a few questions left. That means the conversion with IEnumerable is covariant right? Is it somehow possible to use for example the `ICollection<>`-List? Theoretically the `ICollection<>` just needs to be covariant with an `` doesn't it? Also, why did I saw some examples of people using the `ObservableCollection<>` which didn't work for me? And I tried the conversion where you wrote "ok" and "not ok" and for me it works? When I am in a breakpoint there and look at the values I got a specified amount of elements in both lists? – Heenne Feb 22 '18 at 11:15
  • Sorry, I can't tell. I have no idea what you have seen. And the breakpoint isn't hit at all when I change the property type to `ICollection`. Declaring the property as `IEnumerable` doesn't mean that at runtime the information about the actual type is lost. The runtime (e.g. in your debugger) still knows that it's a `List`. – Clemens Feb 22 '18 at 11:34
  • I edited my post so the code is there and better formatted. That is right where I created the test objects in my TestWrapperViewModel in the GenerateTestObjects-method – Heenne Feb 22 '18 at 11:36
  • Ah, ignore that. I found the mistake in my cast. I casted from `TestingViewModel` to `TestingViewModel` and not from `TestingViewModel` to `ITreeListStructure`. Thanks a lot for your help!!! – Heenne Feb 22 '18 at 11:46