views:

445

answers:

2

Hi,

I'm using the wpf toolkit datagrid to display an observable collection of AccountViewModels.

The thing is when I delete an account from the grid, I want it removed from the ObservableCollection - to give the user visual feedback, but i want the underlying list of Account models to remain the same, just with an 'IsDeleted' flag set on the Account model.

Then whenever the changes are committed, my service knows which accounts to add/update or delete in the database.

Im subscribing to the CollectionChanged event:

AccountViewModels.CollectionChanged += AccountsChanged;

and then setting the viewmodels' model isdeleted flag to true whenever something is removed:

private void AccountsChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null)
        {
            foreach (AccountViewModel model in e.NewItems)
            {
                model.PropertyChanged += accountPropertyChanged;
                model.Account.IsNew = true;
            }
        }
        if (e.OldItems != null)
        {

            foreach (AccountViewModel model in e.OldItems)
            {
                model.PropertyChanged -= accountPropertyChanged;
                model.Account.IsDeleted = true;
            }
        }
    }

but obviously this then removes it from the observable collection. So when I come to commit the changes, there will be no accounts with IsDeleted flag set. i.e. they will have already been removed.

 foreach (AccountViewModel acc in m_ViewModel.AccountViewModels)
        {
            WorkItem workItem = null;
            if(acc.Account.IsNew)
                workItem = new WorkItem("Saving new account: " + acc.AccountName, "Saving new account to the database", () => Service.AddAccount(acc.Account));
            else if (acc.Account.IsDeleted)
                workItem = new WorkItem("Removing account: " + acc.AccountName, "Setting account inactive in the database", () => Service.RemoveAccount(acc.Account));
            else if(acc.Account.IsDirty)
                workItem = new WorkItem("Updating account: " + acc.AccountName, "Updating account in the database", () => Service.UpdateAccount(acc.Account));

            workItems.Add(workItem);

        }

So does this mean I need to maintain two lists, one list of account models and the other an observable collection of accountviewmodels? This just seems nasty and there must be a better way of doing this.

+1  A: 

I don't think you can do this any better with ObservableCollection, as that class holds its own internal list of objects.

However, if you implement a custom Collection that implements INotifyCollectionChanged and INotifyPropertyChanged, you can let it wrap and filter your source collection.

It could filter on the IsDeleted flag so that these are not visible.

Whenever a user removes an item, you can modify the Domain Model directly, setting the IsDeleted flag to true. However, you will still need an eventing mechanism to be able to raise the appropriate events, but with that approach, you only have a single collection of items.

The custom Collection would simply be a Projection over the Domain Model, with added events.

Mark Seemann
If I go this route, how do i capture the property changed event when one of the fields in my model is edited in the grid. I dont really want my domain model to have to implement INotifyPropertyChanged, this is something that my viewmodel was doing previously.
cjroebuck
That's what I meant when I said that you need to have *some* eventing mechanism in place. Either you can raise an event from your Domain Model (it doesn't need to be INotifiedPropertyChanged - it could be a custom event instead), or you need to explicitly notify the Projecting Collection about the change so that it can raise the correct events. A third option is to have the Projecting Collection polling for changes in the underlying model, but that route is fraught with danger...
Mark Seemann
A: 

hello,

You can find an example here : http://blog.lexique-du-net.com/index.php?post/2010/03/02/M-V-VM-How-to-keep-collections-of-ViewModel-and-Model-in-sync

Hope this help

Jmix90