RejectChanges () с шаблоном проектирования ViewModel и MVVM и обновлением пользовательского интерфейса - PullRequest
2 голосов
/ 13 марта 2012

У меня проблема с DomainContext.RejectChanges () и отражается откат в пользовательском интерфейсе.Вот мой сценарий.

  1. У меня есть Модель (Entity), сгенерированная для использования со службами RIA (я назову это Foo )
  2. У меня есть ViewModel , который оборачивает Foo и расширяет его (я назову это FooViewModel )
  3. У меня есть View , использующий Binding для отображения и обновления данных с использованием FooViewModel
  4. У меня есть "external" ViewModel , который содержит ObservableCollection из FooViewModels
  5. «Внешний» Вид имеет список со списком, связанный с ObservableCollection

По сути, на одном экране есть список FooViewModels ... при выборе элемента отображается дочернее окно для редактирования этого конкретного FooViewModel . FooViewModel обслуживает и список, и дочернее окно.

Редактирование работает просто отлично.Изменение в дочернем окне немедленно отражается в списке, потому что я вызываю RaisePropertyChanged () при обновлении свойств модели представления.

Однако, если я выполняю DomainContext.RejectChanges () ... базовый объект откатывается (все изменения возвращаются, как и ожидалось) ... однако FooViewModel не знает, что это изменение произошло, и, следовательно, пользовательский интерфейс не обновляется.Если я повторно выбираю элемент в списке на первом экране, дочернее окно отображается с откатом изменений (что я и хочу).Хотя список еще не обновлен.

Когда я отклоняю изменения, если я kludge a RaiseProperyChanged () для поля, которое я изменил ... пользовательский интерфейсlistbox обновляется.

Как получить обновление пользовательского интерфейса при отклонении базовой сущности ??И как мне это сделать, не отслеживая, какие свойства viewmodel были откатаны?Должен быть простой способ сделать это, которого я просто упускаю.

Ответы [ 2 ]

2 голосов
/ 14 марта 2012

Можно попробовать использовать событие PropertyChanged для базового объекта Foo, чтобы инициировать передачу RaisePropertyChanged для свойств FooViewModel.

, поэтому сделайте некоторые предположения (поэтому этот код имеет смысл):

  1. У вас есть личные переменные в вашем FooViewModel
    private Foo _foo;
    private DomainContext _context;

  2. У вас есть метод наваш FooViewModel, который вызывает RejectChanges() в контексте вашего домена.

Примерно так:

public void RejectChanges()
{
    _context.RejectChanges();
}
  1. У нас есть метод, который вызывает событие PropertyChanged для нашего FooViewModel

Вот так:

private void RaisePropertyChanged(string propertyName)
{
    var handler = PropertyChanged;

    if(handler != null)
        handler(this, new PropertyChangedEventArgs(propertyName);
}

Хорошо, теперь мы установили это, давайте посмотрим, что именно происходит, когда вы звоните RejectChanges() в контексте домена.

Когда вы звоните RejectChanges() это пузыри вниз через DomainContext до EntityContainer, затем до каждого EntitySet в этом контейнере и затем до каждого Entity в наборе.

Когда-то там (и в EntitySet), он применяет исходные значения, если они были, удаляет объект, если он был добавлен, или добавляет его, если он был удален.Если в значения были внесены изменения, то он применяет их обратно к свойствам.

Таким образом, теоретически все RaisePropertyChanged (), которые генерируются в свойствах сущности, должны запускаться.

ПРИМЕЧАНИЕ: я на самом деле не проверял это.Если это не так, то ничего из этого не работает: P

Таким образом, мы можем подключиться к событию PropertyChanged объекта Foo и вызвать событие PropertyChanged в нашем FooViewModel.

чтобы наш метод RejectChanges() мог выглядеть так:

    public void RejectChanges()
    {
        Func<object, PropertyChangedEventArgs> handler = (sender, e) =>
            {
                RaisePropertyChanged(e.PropertyName);
            };

        _foo.PropertyChanged += handler;

        _context.RejectChanges();

        _foo.PropertyChanged -= handler;
    }

Итак, мы подключаем обработчик событий к нашей сущности Foo, которая вызывает метод FooViewModel.RaisePropertyChanged с помощьюимя свойства, которое изменяется в сущности Foo.

Затем мы отклоняем изменения (что вызывает изменения свойства),

, затем мы отцепляем обработчик событий.

Довольнодолго наматывается, но надеюсь это поможет :) 1072 *

0 голосов
/ 13 марта 2012

Я предполагаю, что вызов DomainContext.RejectChanges() происходит внутри ViewModel, поскольку вы, вероятно, связали это с какой-то командой или методом, вызванным из родительского ViewModel. Поскольку все ваши привязки к данным выполняются в свойствах ViewModel, вам придется вызывать событие изменения свойств, когда вы непосредственно манипулируете моделью вне этих свойств. Что вы, вероятно, уже делаете.

public void RejectChanges()
{
     DomainContext.RejectChanges();
     RaisePropertyChangeOnAll();
}

Как вы реализуете RaisePropertyChangeOnAll() можно сделать просто со списком RaisePropertyChange("...") для каждого свойства, или вы можете сделать это с помощью отражения (если позволяют разрешения Silverlight, не слишком уверены в этом), добавив Атрибут для каждого свойства, которое вы хочу поднять. Найдите все свойства, помеченные им, и вызовите RaisePropertyChanged для значения MemberInfo.Name.

[Raiseable]
public string SomeValue
{
   ...
}

Просто идея, но, возможно, не идеальное решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...