Лучший подход для создания нового окна в WPF, использующем MVVM

В соседнем сообщении: Как ViewModel должен закрыть форму? Я отправил свое видение, как закрыть окна с использованием MVVM. И теперь у меня есть вопрос: как открыть их.

У меня есть главное окно (основное представление). Если пользователь нажимает на кнопку "Show" затем, окно "Demo" (модальное диалоговое окно) должно быть отображено. Что предпочтительный путь состоит в том, чтобы создать и открыть окна с помощью шаблона MVVM? Я вижу два общих подхода:

1-й (вероятно, самое простое). Обработчик событий "ShowButton_Click" должен быть реализован в коде позади главного окна способом как это:

        private void ModifyButton_Click(object sender, RoutedEventArgs e)
        {
            ShowWindow wnd = new ShowWindow(anyKindOfData);
            bool? res = wnd.ShowDialog();
            if (res != null && res.Value)
            {
                //  ... store changes if neecssary
            }
        }
  1. Если мы, "Выставочное" состояние кнопки должно быть изменено (позволили/отключили), мы должны будем добавить логику, которая будет управлять состоянием кнопки;
  2. Исходный код очень похож на WinForms "старого стиля" и источники MFC - я не уверенный, если это хорошо или плохо, советуйте.
  3. Что-то еще, что я пропустил?

Другой подход:

В MainWindowViewModel мы реализуем свойство "ShowCommand", которое возвратит интерфейс ICommand команды. Comman в свою очередь:

  • повысит "ShowDialogEvent";
  • будет управлять состоянием кнопки.

Этот подход более подойдет для MVVM, но потребует дополнительного кодирования: класс ViewModel не может "показать диалоговое окно", таким образом, MainWindowViewModel только повысит "ShowDialogEvent", MainWindowView, мы должны будем добавить обработчик событий в его методе MainWindow_Loaded, чем-то вроде этого:

((MainWindowViewModel)DataContext).ShowDialogEvent += ShowDialog;

(ShowDialog - подобный методу 'ModifyButton_Click'.)

Таким образом, мои вопросы: 1. Делаете Вы видите какой-либо другой подход? 2. Делаете Вы думаете, что один из перечисленных хорош или плох? (почему?)

Любые другие мысли приветствуются.

Спасибо.

55
задан Community 23 May 2017 в 01:53
поделиться

5 ответов

Недавно я тоже думал об этой проблеме. Вот идея, которая у меня возникла, если вы используете Unity в своем проекте как «контейнер» или что-то еще для внедрения зависимостей. Я предполагаю, что обычно вы переопределяете App.OnStartup () и создаете свою модель, модель просмотра и просмотр там, и даете каждому соответствующие ссылки. Используя Unity, вы даете контейнеру ссылку на модель, а затем используете контейнер для «разрешения» представления. Контейнер Unity внедряет вашу модель представления, поэтому вы никогда не создаете ее напрямую. Как только ваше представление разрешено, вы вызываете для него Show () .

В примере видео, который я смотрел, контейнер Unity был создан как локальная переменная в OnStartup .Что, если бы вы создали его как общедоступное статическое свойство только для чтения в своем классе приложения? Затем вы можете использовать его в своей основной модели представления для создания новых окон, автоматически вводя любые ресурсы, необходимые новому представлению. Что-то вроде App.Container.Resolve () .ShowDialog (); .

Я полагаю, вы могли бы каким-то образом имитировать результат этого вызова контейнера Unity в своих тестах. В качестве альтернативы, возможно, вы могли бы написать такие методы, как ShowMyChildView () в классе App, который в основном выполняет то, что я описал выше. Было бы легко смоделировать вызов App.ShowMyChildView () , поскольку он просто вернет bool? , а?

Ну, это может быть не лучше, чем просто использовал new MyChildView () , но это небольшая идея, которая у меня была. Я думал, что поделюсь им. =)

16
ответ дан 7 November 2019 в 07:30
поделиться

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

Это выглядит что-то подобное:

class MainViewModel {
    public MainViewModel(IView view, IModel model, IController controller) {
       mModel = model;
       mController = controller;
       mView = view;
       view.DataContext = this;
    }

    public ICommand ShowCommand = new DelegateCommand(o=> {
                  mResult = controller.GetSomeData(mSomeData);
                                                      });
}

class Controller : IController {
    public void OpenMainView() {
        IView view = new MainView();
        new MainViewModel(view, somemodel, this);
    }

    public int GetSomeData(object anyKindOfData) {
      ShowWindow wnd = new ShowWindow(anyKindOfData);
      bool? res = wnd.ShowDialog();
      ...
    }
}
1
ответ дан 7 November 2019 в 07:30
поделиться

Посмотрите на мое текущее решение MVVM для отображения модальных диалогов в Silverlight. Он решает большую часть вопросов, которые вы упомянули, все это полностью абстрагированы от конкретных вещей на платформе и могут быть повторно использованы. Также я не использовал код - позади только привязку с делегатекомами, которые реализуют ICOMBAND. Диалог в основном представление - отдельное управление, которое имеет свой собственный ViewModel, и он отображается с ViewModel главного экрана, но срабатывает с использованием UI через обязательство DelagateCommand.

См. Решение Full Silverlight 4 здесь Модальные диалоги с MVVM и Silverlight 4

2
ответ дан 7 November 2019 в 07:30
поделиться

Мой подход похож на подход Адриана. Однако, в моем случае контроллер никогда не работает с конкретными типами View. Контроллер полностью отделен от вида - так же, как и ViewModel.

Как это работает, можно посмотреть на примере ViewModel из WPF Application Framework (WAF) .

.

Best Regards,

jbe

0
ответ дан 7 November 2019 в 07:30
поделиться

Некоторые структуры MVVM (например, MVVM Light ) используют ] Шаблон посредника . Итак, чтобы открыть новое окно (или создать любое представление), некоторый специфичный для представления код будет подписываться на сообщения от посредника, и ViewModel будет отправлять эти сообщения.

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

Подписка

Messenger.Default.Register<DialogMessage>(this, ProcessDialogMessage);
...
private void ProcessDialogMessage(DialogMessage message)
{
     // Instantiate new view depending on the message details
}

В ViewModel

Messenger.Default.Send(new DialogMessage(...));

я предпочитаю делать подписку в одноэлементном классе, который «живет», пока живет UI-часть приложения. Чтобы Подведем итог: ViewModel передает сообщения типа «Мне нужно создать представление», а пользовательский интерфейс прослушивает эти сообщения и действует в соответствии с ними.

Конечно, нет "идеального" подхода.

17
ответ дан 7 November 2019 в 07:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: