WPF: Как правильно с точки зрения концепции MVVM вызывать новое окно командой ?

263
08 октября 2017, 22:05

Без шаблона MVVM, вызов нового окна в приложениях WPF довольно прост:

// Обработчик кнопки открытия другого окна
void OpenOtherWindow(object sender, RoutedEventArgs e) {
    OtherWindow otherWindow = new OtherWindow();
    otherWindow.ViewModel = "ViewModel"; 
    otherWindow.Show();
    otherWindow.ShowViewModel();
}
// Другое окно
public partial class OtherWindow : Window {
    public string ViewModel { get; set; }
        public OtherWindow(){
            InitializeComponent();
        }
        public void ShowViewModel(){
            MessageBox.Show(ViewModel);
        }
}

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

MainWindowView.xaml (Элемент View)

<Window.CommandBindings>
    <CommandBinding Command="local:AutomationCommands.OpenOtherWindow" Executed="OpenOtherWindow_Executed"/>
</Window.CommandBindings>

MainWindowView.xaml.cs

private void OpenOtherWindow_Executed(object sender, ExecutedRoutedEventArgs e) {
    OtherWindow otherWindow = new OtherWindow();
    otherWindow.ViewModel = "ViewModel"; 
    otherWindow.Show();
    otherWindow.ShowViewModel();
}

AutomationCommands.cs

public static RoutedCommand OpenList = new RoutedCommand("OpenOtherWindow", typeof(AutomationCommands), new InputGestureCollection(){
        new KeyGesture(Key.N, ModifierKeys.Control)
});

Согласно концепции шаблона MVVM, в MainWindowView.xaml.cs особо логики быть не должно. Какие альтернативные, более правильные с точки зрения MVVM подходы Вы можете преложить?

Answer 1

Очень хороший вопрос. Открытие новых окон — это сложный момент в рамках паттерна MVVM.

Смотрите. С одной стороны, решение об открытии нового окна принадлежит уровню бизнес-логики, то есть, VM. С другой стороны, VM не имеет права ничего знать о View. Получается противоречие.

Обычно это противоречие решают, создавая дополнительный сервис открытия окон, который настраивается в начале работы программы, и лежит между VM и View. С таким подходом VM-код создаёт VM-объект некоторого типа, и просит сервис обеспечить показ. Сервис проверяет тип объекта, создаёт окно нужного типа, и показывает его, установив переданный объект в качестве DataContext.

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

Вам ещё придётся организовывать логику, оповещающую сервис о закрытии окна (и, возможно, запрашивающую подтверждение этого в VM).

Answer 2

Как вариант, можно воспользоваться классическим паттерном "Команда", как показано здесь. Тогда, в идеале, можно достичь того, что в представлении останется только инициализация модели представления.

READ ALSO
Не удается подключиться к серверу со статическим IP

Не удается подключиться к серверу со статическим IP

ПриветсвтуюНаписал на c# простое приложение клиент-сервер

272
C# Как отредактировать текст, выведенный в консоль

C# Как отредактировать текст, выведенный в консоль

Помогите пожалуйстаМне нужно, чтобы пользователь мог вводить символы (на месте курсора), и введенные данные отображались в том же месте (на месте...

234
Как собрать .NET Framework

Как собрать .NET Framework

https://githubcom/microsoft/referencesource

254
Использовать Websocket в контроллере asp.net core mvc

Использовать Websocket в контроллере asp.net core mvc

Как использовать websocket в контроллерах aspnet core mvc?

232