views:

460

answers:

2

Hi, any help with this would be great.

I have a model

public class Master
{
   ...
   public Detail[] Details {get; set;}
}

I am populating my view model from a WCF service which returns my collection of Master objects. I have configured the service reference to return observablecollection so I can use it easily in my view model.

My view model then has

public ObservableCollection<Master> Masters {get; set;}
public Master SelectedMaster {get; set;}

In my view I have 2 listboxes - one bound to my Masters property and the other bound to SelectedMaster.Details.

This all works fine apart from when I add try to add a new detail to the SelectedMaster.

The collection of Details in the SelectedMaster is just a list of Details (not an ObservableCollection) which is clearly why.

What options do I have here? I have tried implementing INotifyPropertyChanged but that doesn't seem to work. I could have another ObservableCollection for the Details but that means I have to keep this collection in sync when the SelectedMaster is changed (the SelectedMaster property is bound to the SelectedItem on my first listbox.

Hope this comes across OK. Would really love some feedback. Would be ideal if WCF could just return the collection of details as an observablecollection as it does with the collection of Masters but it doesn't seem to work like that.

Thanks.

+1  A: 

I don't know enough WCF to say whether it can be configured to return nested collections as other types than simple arrays, but I'll try to give the WPF perspective.

There's no magic here, a simple array doesn't implement any kind of change notification; you simply have to wrap it in some kind of view-aware collection such as ObservableCollection.

Wrap everything up and only interact with the wrapped collections, example:

public class MasterWrapper
{
...
    public MasterWrapper(Master master)
    {
        this.Details = new ObservableCollection<Detail>();
        this.Master = master;
        foreach (var detail in Master.Details)
            this.Details.Add(detail);
    }
...

    public static ObservableCollection<MasterWrapper> GetMasters()
    {
        ObservableCollection<MasterWrapper> results = 
            new ObservableCollection<MasterWrapper>();
        List<Master> modelMasters = null; // Populate this from the service.
        foreach (var m in modelMasters)
            results.Add(new MasterWrapper(m));
        return results;
    }
Aviad P.
+1 your answer is definitely cleaner; I think I'll leave my answer up as the quick 'n easy alternative, but this is the way I would do it :)
IanR
+1  A: 

You're right that the issue is that the Details property does not have changes notified back to the View, because it is just an array of Detail objects...

I would make it an ObservableCollection<Detail> and load up the collection in Master's constructor, like...

public Master(Detail[] details)
{
    Details = new ObservableCollection<Detail>(details);
}

remember that ObservableCollection<T> takes IEnumerable<T> or List<T> as a parameter in its constructor.

IanR
OK I think I see what you mean. Thanks for your reply.What I think I'm a little unclear on is that I was thinking the view model would be the only place where I thought I'd be using things such as observableCollection (as it's only really needed to help support the UI). Doing it this way I'm now changing my model to include something that is only really necessary for the UI. Is that the right thing to do?
David Shaw
See my answer, wrap both `Master` and `Detail` to make for better decoupling, and to avoid introducing view dependency into your model.
Aviad P.