Форум программистов, компьютерный форум, киберфорум
bodynar
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  

Открытие новых диалогов

Запись от bodynar размещена 20.05.2016 в 16:47
Показов 2729 Комментарии 0
Метки c#, mvvm, wpf

Не так давно, в ходе изучения MVVM-паттерна, наткнулся на такой вопрос: "А как все-таки открывать новые диалоговые окна (View) из ViewModel?".
Небольшая справка
MVVM - Model-View-ViewModel - паттерн проектирования приложений. Очень хорошо реализуется в WPF благодаря привязкам (Bindings).
Модель (Model) - Модель данных, Например:
Кликните здесь для просмотра всего текста
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Student 
{
    string FirstName;
    string SecondName;
    int Age;
    double mark;
    
    //...
    
    func void SetMark(double mark) {
        self.mark = mark;
    }
    //...
}
.

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

Модель представления (ViewModel) является, с одной стороны, абстракцией Представления, а с другой, предоставляет обёртку данных из Модели, которые подлежат связыванию. То есть, она содержит Модель, которая преобразована к Представлению, а также содержит в себе команды, которыми может пользоваться Представление, чтобы влиять на Модель.
(с) Вики


По принципу MVVM ViewModel не знает о существовании View, как и View не знает о ViewModel. Этакая обособленность. По этому делать что-то вроде:
C#
1
new MainWindow1().ShowDialog();
внутри ViewModel будет нарушением использования паттерна.

Через некоторое время путешествия по интернету в поисках хорошего работоспособного и паттерно-чистого решения наткнулся на одного человека, который посоветовал использовать некий сервис, который будет выполнять всю грязную работу. Ранее уже выкладывал сей способ в одной из тем форума в разделе WPF.
C#
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
public interface IDialogService
    {
        bool? ShowDialog(ViewModelBase vm);
 
        MessageBoxResult MessageBox(string messageBoxText, string caption);
 
        MessageBoxResult MessageBox(string messageBoxText, string caption, MessageBoxButton button);
 
        MessageBoxResult MessageBox(string messageBoxText, string caption, MessageBoxButton button,
            MessageBoxImage iconImage);
    }
 
public class DialogService : IDialogService
    {
        private static DialogService _default;
        private readonly Stack<Window> _parents = new Stack<Window>();
 
        private readonly IDictionary<Type, Type> _windows = new Dictionary<Type, Type>();
 
        public DialogService(Window mainWindow)
        {
            _parents.Push(mainWindow);
        }
 
        public DialogService()
        {
        }
 
        public static DialogService Default => _default ?? (_default = new DialogService());
 
        public bool? ShowDialog(ViewModelBase vm)
        {
            var vmType = vm.GetType();
            if (!_windows.ContainsKey(vmType))
                throw new ArgumentException("no registerd window for type " + vmType.Name);
 
            var viewType = _windows[vmType];
 
            var view = (Window) Activator.CreateInstance(viewType);
            view.DataContext = vm;
            view.Owner = _parents.Peek();
 
            view.Closed += WindowClosed;
            _parents.Push(view);
 
            return view.ShowDialog();
        }
 
        public MessageBoxResult MessageBox(string messageBoxText, string caption)
        {
            return WPF.MessageBox.Show(_parents.Peek(), messageBoxText, caption);
        }
 
        public MessageBoxResult MessageBox(string messageBoxText, string caption, MessageBoxButton button)
        {
            return WPF.MessageBox.Show(_parents.Peek(), messageBoxText, caption, button);
        }
 
        public MessageBoxResult MessageBox(string messageBoxText, string caption, MessageBoxButton button,
            MessageBoxImage iconImage)
        {
            return WPF.MessageBox.Show(_parents.Peek(), messageBoxText, caption, button, iconImage);
        }
 
        public void SetMainParent(Window window)
        {
            _parents.Clear();
            _parents.Push(window);
        }
 
        public void Register<T, TK>()
            where T : ViewModelBase
            where TK : Window
        {
            _windows.Add(typeof (T), typeof (TK));
        }
 
        private void WindowClosed(object sender, EventArgs e)
        {
            var view = (Window) sender;
            view.Closed -= WindowClosed;
            _parents.Pop();
 
            var vm = view.DataContext as IDisposable;
            vm?.Dispose();
        }
    }
Насколько можно видеть - данный сервис позволяет произвести связывание ViewModel и View, который будет отображать данные из первого и отображение View по заданному ViewModel.

То есть - у нас имеется место в приложении, где нам необходимо отобразить следующее окно с какой-либо информацией. Для этого мы создаем в нужном месте ViewModel, в котором будут содержаться требуемые данные и "просим сервис отобразить данный ViewModel".

Таким образом, определив в App.xaml обработчик события Startup и в App.xaml.cs в обработчике этого пропишем что-то вроде:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
var _dialogService = DialogService.Default;
 
            _dialogService.Register<FirstViewModel, FirstView>();
 
            _dialogService.Register<SecondViewModel, SecondView>();
 
            _dialogService.Register<ThirdViewModel, ThirdView>();
 
            var v = new SecondView();
            var vm = new SecondViewModel(_dialogService);
            v.DataContext = vm;
            _dialogService.SetMainParent(v);
            v.ShowDialog();
И, допустим, в SecondViewModel у нас имеется метод, "вызывающий другое окно":
C#
1
2
var fvm = new FirstViewModel(editedperson);
_dialogService.ShowDialog(fvm));
Таким образом у нас имеется более-менее чистый способ решения вопроса об открытии других окон в рамках паттерна MVVM.

PS. Как можно было заметить - DialogService реализует паттерн синглтон. Как к нему относится - дело ваше. Человек, посоветовавший данный способ не слишком позитивно отзывался о данном паттерне, посему рекомендовал "протаскивать" ранее созданный _dialogService по всем ViewModel (с помощью передачи его в качестве аргумента в конструктор ViewModel)
Метки c#, mvvm, wpf
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Отчёт о затраченных материалах за определенный период с макетом печатной формы
Maks 21.04.2026
Отчёт из решения ниже размещён в конфигурации КА2. Задача: разработка отчёта по затраченным материалам за определённый период, с возможностью вывода печатной формы отчёта с шапкой и подвалом. В. . .
Отчёт о спецтехнике находящейся в ремонте
Maks 20.04.2026
Отчёт из решения ниже размещен в конфигурации КА2. Задача: отобразить спецтехнику, которая на данный момент находится в ремонте. Есть нетиповой документ "Заявка на ремонт спецтехники" который. . .
Памятка для бота и "визитка" для читателей "Semantic Universe Layer (Слой семантической вселенной)"
Hrethgir 19.04.2026
Сгенерировано для краткого описания по случаю сборки и компиляции скелета серверного приложения. И пусть после этого скажут, что статьи сгенерированные AI - туфта и не интересно. И это не реклама -. . .
Запрет удаления строк ТЧ документа при определённом условии
Maks 19.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "Аккумуляторы", разработанного в конфигурации КА2. У данного документа есть ТЧ, в которой в зависимости от прав доступа. . .
Модель заражения группы наркоманов
alhaos 17.04.2026
Условия задачи сформулированы тут Суть: - Группа наркоманов из 10 человек. - Только один инфицирован ВИЧ. - Колются одной иглой. - Колются раз в день. - Колются последовательно через. . .
Мысли в слух. Про "навсегда".
kumehtar 16.04.2026
Подумалось тут, что наверное очень глупо использовать во всяких своих установках понятие "навсегда". Это очень сильное понятие, и я только начинаю понимать край его смысла, не смотря на то что давно. . .
My Business CRM
MaGz GoLd 16.04.2026
Всем привет, недавно возникла потребность создать CRM, для личных нужд. Собственно программа предоставляет из себя базу данных клиентов, в которой можно фиксировать звонки, стадии сделки, а также. . .
Знаешь почему 90% людей редко бывают счастливыми?
kumehtar 14.04.2026
Потому что они ждут. Ждут выходных, ждут отпуска, ждут удачного момента. . . а удачный момент так и не приходит.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru