Как мне справиться с этим распространенным сценарием пользовательского интерфейса в MVVM? - PullRequest
1 голос
/ 20 августа 2010

Сценарий:

  1. Родительское окно загружает, заполняет данные (сетка, метки и т. Д.)
  2. Пользователь нажимает кнопку, вызывая связанную командув ViewModel родительского окна, запуская диалог редактирования
  3. Пользователь вносит изменения в диалоговое окно редактирования и нажимает «Принять», сохраняя некоторую информацию в базе данных
  4. ViewModel родительского окна распознает, что что-то произошлочто dialog.DialogResult == true), и что он должен обновить свои данные и любые соответствующие привязки

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

ViewModel не должен (насколько я понимаю) много знать / что-либо о своем связанном View, и поэтому ViewModel будет трудно взаимодействовать с View:

"Эй, операция сохранения успешно завершена! Идите и закройте сейчас! "

Или:

" Ого! Возникла проблема, о которой нужно позаботиться, прежде чемВы можете закрыть ... подождите галочку. "

Вопрос:

Как что-то подобное элегантно выполнено, скак можно меньше xaml.cs кода (желательно ни одного)?

Ответы [ 4 ]

3 голосов
/ 20 августа 2010

Обычно, когда я делаю что-то подобное, я передаю открытие диалоговых окон сервису, который позже можно смоделировать для целей тестирования. Что-то вроде:

public interface IDialogProvider
{
      bool OpenDialog(IViewModel viewModel)
}

Тогда переданная в viewmodel граница может быть установлена ​​как DataContext модального окна, и через шаблоны данных будет использоваться правильный вид.

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

public void ExecuteEdit()
{
    ChildViewModel childViewModel = GetViewModelForSelectedItem();
    if (_dialogProvider.OpenDialog(childViewModel)
    {
        //child view model saved, trigger rebinding etc...
    }
}

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

public DialogWindowView()
{
    InitializeComponent();
    DataContexctChanged += HandleDataContextChanged;
}

private void HandleDataContextChanged(object sender, EventArgs e)
{ 
    IDialogViewModel viewModel = DataContext as IDialogViewModel;

    if (viewModel != null)
    {
         viewModel.ActionSuccessful += HandleActionSuccessful
    }
}

private void HandleActionSuccessful(object sender, EventArgs e)
{
     DialogResult = DialogResult.OK;
     Close();
} 

У меня нет никаких проблем с тем, что этот код является представлением, поскольку он не отвечает за то, как выглядит модель, включая открытие или закрытие окон. Если вы полностью против идеи кода или вы не хотите связывать представление с типом модели представления, вы можете вместо этого перенести ответственность на DialogProvider:

public class DialogProvider : IDialogProvider
{
  public bool OpenDialog(IDialogViewModel viewModel)
  {
       Window dialog = new DialogWindow();
       dialog.DataContext = viewModel;
       bool success = false;
       viewModel.ActionSuccessful = (o, e) => 
         {
              dialog.Close();
              success = true;
         }

      dialog.ShowDialog();

      return success;
  }
}
1 голос
/ 20 августа 2010

Хороший вопрос.
Шаблон MVVM утверждает, что представление должно привязывать данные к ViewModel.Properties. View может инициировать действия, вызывая ViewModel.Commands (View => VM).
Следовательно, ViewModel может сообщать что-либо обратно только через View (Свойства) (т.е. PropertyChangedNotifications). Представление должно будет привязаться к какому-либо свойству на виртуальной машине, а при изменении решить, закрывать себя или нет.

1 голос
/ 20 августа 2010

Ваш EditDialog может иметь свойство IsVisible, с которым связан видимость диалога. Если сохранение не удалось, оставьте для свойства IsVisible значение true, в противном случае установите для него значение false. Поскольку он привязан, он должен автоматически скрывать всплывающее окно при успешном завершении сохранения или оставлять его открытым в случае сбоя.

0 голосов
/ 22 августа 2010

Я свернул свой собственный загрузчик окон, который описан в моем ответе здесь:

Управление несколькими представлениями WPF в приложении

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