Как синхронизировать коллекции моделей просмотра и моделей

Я использую сетку данных набора инструментов wpf для отображения наблюдаемой коллекции AccountViewModels.

Дело в том, что когда я удаляю учетную запись из сетки, я хочу, чтобы она была удалена из ObservableCollection, чтобы дать пользователю визуальную обратную связь, но я хочу, чтобы базовый список моделей учетных записей оставался прежним, просто с установленным флагом «IsDeleted». Модель счета.

Затем всякий раз, когда изменения фиксируются, моя служба знает, какие учетные записи добавлять/обновлять или удалять в базе данных.

Я подписываюсь на событие CollectionChanged:

AccountViewModels.CollectionChanged += AccountsChanged;

а затем установить флаг isdeleted модели представления в true всякий раз, когда что-то удаляется:

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;
            }
        }
    }

но, очевидно, это удаляет его из наблюдаемой коллекции. Поэтому, когда я приду, чтобы зафиксировать изменения, не будет учетных записей с установленным флагом IsDeleted. то есть они уже будут удалены.

 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);

        }

Значит ли это, что мне нужно поддерживать два списка, один список моделей учетных записей, а другой — наблюдаемую коллекцию моделей просмотра учетных записей? Это просто кажется неприятным, и должен быть лучший способ сделать это.


person cjroebuck    schedule 26.01.2010    source источник


Ответы (2)


Я не думаю, что вы можете сделать это лучше с ObservableCollection, так как этот класс содержит свой собственный внутренний список объектов.

Однако если вы реализуете пользовательскую коллекцию, которая реализует INotifyCollectionChanged и INotifyPropertyChanged, вы можете позволить ей обернуть и отфильтровать вашу исходную коллекцию.

Он может фильтровать флаг IsDeleted, чтобы они не были видны.

Всякий раз, когда пользователь удаляет элемент, вы можете напрямую изменить модель предметной области, установив для флага IsDeleted значение true. Однако вам по-прежнему потребуется механизм обработки событий, чтобы иметь возможность вызывать соответствующие события, но при таком подходе у вас будет только одна коллекция элементов.

Пользовательская коллекция будет просто проекцией на модель предметной области с добавленными событиями.

person Mark Seemann    schedule 26.01.2010
comment
Если я пойду по этому пути, как мне зафиксировать событие изменения свойства, когда одно из полей в моей модели редактируется в сетке. Я действительно не хочу, чтобы моя модель домена реализовывала INotifyPropertyChanged, это то, что моя модель представления делала ранее. - person cjroebuck; 26.01.2010
comment
Именно это я имел в виду, когда говорил, что вам нужен некоторый механизм обработки событий. Либо вы можете инициировать событие из вашей модели предметной области (это не обязательно должно быть INotifiedPropertyChanged — вместо этого это может быть пользовательское событие), либо вам необходимо явно уведомить коллекцию проецирования об изменении, чтобы она могла вызывать правильные события. Третий вариант — опрос Projecting Collection на предмет изменений в базовой модели, но этот путь чреват опасностью... - person Mark Seemann; 26.01.2010

Вы можете найти пример здесь: 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

Надеюсь, это поможет

person Jonathan ANTOINE    schedule 02.03.2010