Лучшее место, чтобы открыть новое окно в Model View ViewModel - PullRequest
9 голосов
/ 17 марта 2009

У меня есть приложение MVVM. В одной из ViewModels есть FindFilesCommand, который заполняет ObservableCollection. Затем я реализую «RemoveFilesCommand» в той же модели представления. Затем эта команда вызывает окно, чтобы получить больше пользовательского ввода.

Где / как лучше всего это сделать, придерживаясь парадигмы MVVM? как-то делать:

new WhateverWindow( ).Show( ) 

в ViewModel кажется неправильным.

Приветствия

Steve

Ответы [ 7 ]

2 голосов
/ 13 сентября 2009

Лично я рассматриваю этот сценарий как сценарий, в котором модель представления основного окна хочет выполнить задачу для конечного пользователя.

Он должен отвечать за создание задачи и ее инициализацию. Представление должно отвечать за создание и отображение дочернего окна и использование задачи в качестве модели представления вновь созданного окна.

Задание может быть отменено или совершено. По завершении оно выдает уведомление.

Окно использует уведомление, чтобы закрыть себя. Модель родительского представления использует уведомление для выполнения дополнительной работы после выполнения задачи, если есть последующая работа.

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

У меня есть реализация этого для Silverlight. См. http://www.nikhilk.net/ViewModel-Dialogs-Task-Pattern.aspx для получения более подробной информации ... Я хотел бы услышать комментарии / дополнительные предложения по этому вопросу.

1 голос
/ 19 марта 2009

Onyx (http://www.codeplex.com/wpfonyx) предоставит довольно хорошее решение для этого. В качестве примера рассмотрим сервис ICommonDialogProvider, который можно использовать из ViewModel, например:

ICommonFileDialogProvider provider = this.View.GetService<ICommonDialogProvider>();
IOpenFileDialog openDialog = provider.CreateOpenFileDialog();
// configure the IOpenFileDialog here... removed for brevity
openDialog.ShowDialog();

Это очень похоже на использование конкретного OpenFileDialog, но полностью тестируемо. Степень развязки, которая вам действительно нужна, будет для вас деталью реализации. Например, в вашем случае вам может понадобиться сервис, который полностью скрывает тот факт, что вы используете диалог. Что-то вроде:

public interface IRemoveFiles
{
   string[] GetFilesToRemove();
}

IRemoveFiles removeFiles = this.View.GetService<IRemoveFiles>();
string[] files = removeFiles.GetFilesToRemove();

Затем необходимо убедиться, что в представлении есть реализация службы IRemoveFiles, для которой есть несколько доступных вариантов.

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

1 голос
/ 18 марта 2009

В примере с Южным мостом Хайме Родригесу и Карлу Шиффлету они создают окно в модели представления, более конкретно в части выполнения связанной команды:

    protected void OnShowDetails ( object param ) 
    {
        // DetailsWindow window = new DetailsWindow();
        ListingDetailsWindow window = new ListingDetailsWindow();
        window.DataContext = new ListingDetailsViewModel ( param as Listing, this.CurrentProfile ) ; 
        ViewManager.Current.ShowWindow(window, true); 
    } 

Вот ссылка: http://blogs.msdn.com/jaimer/archive/2009/02/10/m-v-vm-training-day-sample-application-and-decks.aspx

Полагаю, это не большая проблема. В конце концов, Viewmodel действует как «связующее звено» между представлением и бизнес-уровнем / уровнем данных, поэтому, как правило, соединение с представлением (UI) является нормальным ...

0 голосов
/ 19 июля 2010

То, что мы делаем, примерно так, что описано здесь: http://www.codeproject.com/KB/WPF/DialogBehavior.aspx?msg=3439968#xx3439968xx

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

0 голосов
/ 18 марта 2009

Я бы сказал, что услуги - это путь сюда.

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

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

0 голосов
/ 18 марта 2009

Я столкнулся с этой проблемой и с MVVM. Моя первая мысль - попытаться найти способ не использовать диалог. Используя WPF, гораздо проще придумать более изящный способ сделать что-либо, чем диалоговое окно.

Когда это невозможно, наилучшим вариантом, по-видимому, является использование ViewModel для вызова класса Shared для получения информации от пользователя. ViewModel не должен знать, что отображается диалоговое окно.

Итак, в качестве простого примера, если вам нужно, чтобы пользователь подтвердил удаление, ViewModel может вызвать DialogHelper.ConfirmDeletion (), который будет возвращать логическое значение того, сказал ли пользователь да или нет. Фактическое отображение диалога будет выполнено в классе Helper.

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

Я согласен, что это не самое гладкое соответствие с остальными MVVM, но я не нашел лучших примеров.

0 голосов
/ 17 марта 2009

Для диалогов такого рода. Я определяю его как вложенный класс FindFilesCommand. Если основной диалог используется среди многих команд, я определяю его в модуле, доступном для этих команд, и заставляю команду соответствующим образом настроить диалог.

Объектов команды достаточно, чтобы показать, как диалог взаимодействует с остальной частью программного обеспечения. В моем собственном программном обеспечении объекты Command находятся в своих собственных библиотеках, поэтому диалоги скрыты от остальной системы.

По моему мнению, делать что-либо более излишнее Кроме того, пытаясь поддерживать его на самом высоком уровне, часто приходится создавать множество дополнительных интерфейсов и методов регистрации. Много кода для небольшого усиления.

Как и в любом другом случае, рабская преданность приведет вас в странные проходы. Вы должны использовать суждение, чтобы увидеть, есть ли другие методы, которые можно использовать, когда вы получаете неприятный запах кода. Опять же, по моему мнению, диалоги должны быть тесно связаны и определены рядом с командой, которая их использует. Таким образом, пять лет спустя я могу вернуться к этому разделу кода и посмотреть все, с чем имеет дело команда.

Опять же, в тех немногих случаях, когда диалог полезен для нескольких команд, я определяю его в общем модуле для всех из них. Однако в моем программном обеспечении, возможно, 1 из 20 диалогов выглядит так. Основным исключением является диалог открытия / сохранения файла. Если в диалоге используются десятки команд, я бы прошел полный путь определения интерфейса, создания формы для реализации этого интерфейса и регистрации этой формы.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...