Уведомить пользователя из ViewModel и отменить навигацию - PullRequest
1 голос
/ 02 сентября 2011

У меня есть представление, которое содержит список элементов, TextBox и кнопку Сохранить.TextBox привязан к свойству выбранного в данный момент элемента списка.DataSource списка привязано к ObservableCollection<T> в ViewModel.
Теперь, когда пользователь выбирает другой элемент в списке и не сохраняет свои изменения в TextBox, его должны спросить,или нет, он хочет отказаться от изменений, которые он сделал.Выбранный элемент в списке должен быть изменен только в том случае, если он ответит «да».
Проблема, с которой я столкнулся, заключается в следующем:
Мне нужно реализовать проверку на изменения в ViewModel, но я не знаю, где,поскольку ViewModel не получает уведомление, когда выбранный элемент изменяется.


Я предложил следующий метод, но он не выглядит чистым:
В списке есть событие SelectedItemsChanging.Я мог бы использовать поведение EventToCommand и передать команду CancelEventArgs в качестве параметра.В команде я проверяю, был ли изменен элемент, и если это так, я мог бы использовать мессенджер для отправки сообщения, которое прослушивает View.Вид затем покажет пользователю диалог подтверждения и вернет результат обратно в ViewModel каким-то образом .ViewModel, в свою очередь, устанавливает свойство Cancel аргументов события на true, если пользователь не хочет отбрасывать свои изменения.
Мне это не кажется чистым, потому что он разрывает эту простую функциональность иразмазывает его по трем файлам, что делает его очень трудным для понимания.
Есть ли рекомендации для такого сценария?

Ответы [ 3 ]

1 голос
/ 02 сентября 2011

Я бы поставил Грязную проверку на класс модели. Пример ниже:

Public m_dirtyFields As New Dictionary(Of String, String)

Private Sub AddDirtyField(ByVal ColName As String, ByVal OrigValue As String)
    If Not m_dirtyFields.ContainsKey(ColName) Then
        m_dirtyFields.Add(ColName, OrigValue)
        OnPropertyChanged("IsDirty")
    End If
End Sub
Private Sub RemoveDirtyField(ByVal ColName As String)
    If m_dirtyFields.ContainsKey(ColName) Then
        m_dirtyFields.Remove(ColName)
    End If
    OnPropertyChanged("IsDirty")
End Sub

Private Sub OnAddress1Changing(ByVal value As String)
    If Not m_dirtyFields.ContainsKey("Address1") Then
        AddDirtyField("Address1", Address1)
    Else
        If m_dirtyFields("Address1") = value Then RemoveDirtyField("Address1")
    End If
End Sub

Public ReadOnly Property IsDirty
    Get
        If _Initialized = False Then
            m_dirtyFields.Clear()
            _Initialized = True
        End If

        If m_dirtyFields.Count > 0 Then
            Return True
        Else : Return False
        End If
    End Get
End Property

Приведенный выше пример проверяет значения свойств, добавляет их в словарь на основе сходства исходных значений и возвращает значение Dirty на основе элементов в словаре.

В вашей ViewModel вы можете просто проверить MyObject.IsDirty и, если он изменился, всплывающее окно сообщения с просьбой сохранить (или нет).

Кроме того, вы можете отключить Listbox (чтобы пользователь не мог изменять записи), когда запись грязная, но имеет свойство ViewModel, которое рекламирует свойство Dirty объекта SelectedItem.

0 голосов
/ 08 марта 2013
0 голосов
/ 13 октября 2011

После еще одного исследования я наткнулся на «шаблон запроса взаимодействия», используемый в PRISM. Это в основном то же решение, которое я уже изложил в своем ответе, только чуть более изощренное. Это то, что я сейчас использую.

Работает так:

  1. ViewModel имеет свойство моего пользовательского интерфейса IInteractionRequest<TInteractionData>. Этот интерфейс содержит только событие Raised.
  2. В представлении поведение связано с этим свойством.

    <i:Interaction.Behaviors>
        <Interaction:NotificationMessageBoxBehavior
             SourceObject="{Binding NotificationRequest}" />
    </i:Interaction.Behaviors>
    

    Связанное поведение (в примере NotificationMessageBoxBehavior) определяет, как обрабатывается запрос взаимодействия. Например, в приложении Windows это просто вызывает MessageBox.Show, но может быть альтернативная реализация, которая работает в приложениях Silverlight.
    Все поведения получены из общего базового класса, который наследуется от Behavior<FrameworkElement> и имеет свойство зависимости SourceObject типа IInteractionRequest<TInteractionData>. Вот как поведение и запрос взаимодействия сводятся воедино: поведение подписывается на событие Raised SourceObject и выполняет запрос взаимодействия при возникновении события.

  3. Конкретная реализация данных взаимодействия, которая используется в запросе, может содержать обратный вызов, который вызывается после завершения запроса. Этот обратный вызов может иметь параметр. Таким образом, результат запроса взаимодействия может возвращаться в ViewModel.

...