В соседнем сообщении: Как 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
}
}
Другой подход:
В MainWindowViewModel мы реализуем свойство "ShowCommand", которое возвратит интерфейс ICommand команды. Comman в свою очередь:
Этот подход более подойдет для MVVM, но потребует дополнительного кодирования: класс ViewModel не может "показать диалоговое окно", таким образом, MainWindowViewModel только повысит "ShowDialogEvent", MainWindowView, мы должны будем добавить обработчик событий в его методе MainWindow_Loaded, чем-то вроде этого:
((MainWindowViewModel)DataContext).ShowDialogEvent += ShowDialog;
(ShowDialog - подобный методу 'ModifyButton_Click'.)
Таким образом, мои вопросы: 1. Делаете Вы видите какой-либо другой подход? 2. Делаете Вы думаете, что один из перечисленных хорош или плох? (почему?)
Любые другие мысли приветствуются.
Спасибо.
Недавно я тоже думал об этой проблеме. Вот идея, которая у меня возникла, если вы используете Unity в своем проекте как «контейнер» или что-то еще для внедрения зависимостей. Я предполагаю, что обычно вы переопределяете App.OnStartup ()
и создаете свою модель, модель просмотра и просмотр там, и даете каждому соответствующие ссылки. Используя Unity, вы даете контейнеру ссылку на модель, а затем используете контейнер для «разрешения» представления. Контейнер Unity внедряет вашу модель представления, поэтому вы никогда не создаете ее напрямую. Как только ваше представление разрешено, вы вызываете для него Show ()
.
В примере видео, который я смотрел, контейнер Unity был создан как локальная переменная в OnStartup
.Что, если бы вы создали его как общедоступное статическое свойство только для чтения в своем классе приложения? Затем вы можете использовать его в своей основной модели представления для создания новых окон, автоматически вводя любые ресурсы, необходимые новому представлению. Что-то вроде App.Container.Resolve
.
Я полагаю, вы могли бы каким-то образом имитировать результат этого вызова контейнера Unity в своих тестах. В качестве альтернативы, возможно, вы могли бы написать такие методы, как ShowMyChildView ()
в классе App, который в основном выполняет то, что я описал выше. Было бы легко смоделировать вызов App.ShowMyChildView ()
, поскольку он просто вернет bool?
, а?
Ну, это может быть не лучше, чем просто использовал new MyChildView ()
, но это небольшая идея, которая у меня была. Я думал, что поделюсь им. =)
Я использую контроллер, который обрабатывает всю информацию, проходящую между видами. Все 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();
...
}
}
Посмотрите на мое текущее решение MVVM для отображения модальных диалогов в Silverlight. Он решает большую часть вопросов, которые вы упомянули, все это полностью абстрагированы от конкретных вещей на платформе и могут быть повторно использованы. Также я не использовал код - позади только привязку с делегатекомами, которые реализуют ICOMBAND. Диалог в основном представление - отдельное управление, которое имеет свой собственный ViewModel, и он отображается с ViewModel главного экрана, но срабатывает с использованием UI через обязательство DelagateCommand.
См. Решение Full Silverlight 4 здесь Модальные диалоги с MVVM и Silverlight 4
Мой подход похож на подход Адриана. Однако, в моем случае контроллер никогда не работает с конкретными типами View. Контроллер полностью отделен от вида - так же, как и ViewModel.
Как это работает, можно посмотреть на примере ViewModel из WPF Application Framework (WAF) .
.
Best Regards,
jbe
Некоторые структуры 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 передает сообщения типа «Мне нужно создать представление», а пользовательский интерфейс прослушивает эти сообщения и действует в соответствии с ними.
Конечно, нет "идеального" подхода.