Страницы

Поиск по вопросам

воскресенье, 8 декабря 2019 г.

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

#c_sharp #wpf #xaml #mvvm


Без шаблона 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)


    



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 подходы Вы можете преложить?



Обновление (Конкурс)

Несколько часов смотрел разные примеры по данной теме на разных языках. Все они либо
неполные, потому не получается довести их до рабочего приложения, либо слишком сложные,
а потому крайне трудны для понимания и адаптировать их под своё приложение, понимая
при этом что делаешь, невозможно без помощи более опытных wpf-разработчиков. Потому,
в данном конкурсе задача будет такая: 


Сделать минимальное, но рабочее приложение, на основе которого уже можно будет дальше
что-то усложнять.
Ничего лишнего: две кнопки на главном экране; одна открывает обычное окно, другая
- диалоговое (в чём разница в случае с WPF - честно говоря не понимаю, поэтому включите,
пожалуйста, это объяснение в ответ). В новых окнах будет по одной надписи, что окно
успешно открыто. Всё, больше нам в разметке ничего не нужно.







Мы будем придерживаться паттерна MVVM, но в данном примере нам модель не нужна. Также
не уведен, нужна ли ViewModel но на всякий случай добавил соответствующие классы. Таким
образом организация файлом будет такая (папка Models присутствует, но она пустая):





Не надо писать мини-фреймворки - люди, у которых нет опыта разработки в WPF, их не
поймут, а потому не смогут воспользоваться ими с понимаем. Нам нужен только код для
открытия окон (в рамках MVVM - с использование сервисов) а так же оповещение сервисов
для закрытия окна.
Поскольку приложение простейшее, то никаких особых действий при закрытии окна не
будет. Однако прошу Вас добавить пустой метод для обработки закрытия окна, чтобы при
дальнейшем усложнении данного примера было понятно, куда этот метод вставлять (в этом
методе может быть, например, сохранение введённых данных).


Заготовки кода:

MainWindowView.xaml - элемент View главного окна 


    
        


Ответы

Ответ 1



Написано приложение, демонстрирующее открытие и закрытие окон с использованием паттерна MVVM. Так же, команды отвечающие за открытие окон привязаны на горячие клавиши (Ctrl-Y - открыть первое окно, Ctrl-Z - открыть второе окно) Код приложения находится в git https://github.com/bakulev/MVVM_OpenNewWindowMinimalExample Работоспособность приложения проверена. В коде использованы советы описанные в вопросе Сервис создания модальных и немодальных окон в контексте паттерна MVVM

Ответ 2



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

Ответ 3



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

Комментариев нет:

Отправить комментарий