Пример диалога WPF MVVM
Есть ли у кого-нибудь примеры отображения диалогового окна с использованием MVVM (Prism)? - например, окно настроек конфигурации при выполнении команды.
Все примеры, которые я видел, используют шаблон посредника, который хорош, но они также имеют ссылку на представление в модели представления, которое не является идеальным (мы используем DataTemplates)
Спасибо
Ответы
Ответ 1
Я бы использовал сервис для отображения диалога. Затем служба может также связывать представления с режимами просмотра.
public interface IDialogService {
void RegisterView<TView, TViewModel>() where TViewModel:IDialogViewModel;
bool? ShowDialog(IDialogViewModel viewModel);
}
public interface IDialogViewModel {
bool CanClose();
void Close();
}
RegisterView
просто связывает тип вида с типом ViewModel. Вы можете настроить эти ссылки в инициализации модуля. Это проще, чем пытаться получить модули для регистрации datatemplates в верхнем слое вашего приложения.
ShowDialog
Показывает ViewModel, который вы хотите отобразить. Он возвращает true, false и null для закрытия точно так же, как метод Window.ShowDialog
. Реализация просто создает новый вид типа TView
из вашего контейнера, перехватывает его до предоставленного ViewModel и показывает его.
IDialogViewModel
предоставляет механизм ViewModel для проверки и отмены закрытия диалога.
У меня есть стандартное диалоговое окно с элементом управления содержимым. Когда вызывается ShowDialog
, он создает новый стандартный диалог, добавляет представление в элемент управления содержимым, подключает ViewModel и отображает его. Стандартный диалог уже имеет кнопки [OK] и [Cancel] с соответствующей логикой для вызова правильных методов из IDialogViewModel
.
Ответ 2
То, как я это делаю, также использует шаблон медиатора. Когда ViewModel хочет показать диалог, он отправляет сообщение, которое отображает главное окно приложения. Сообщение содержит экземпляр ViewModel, используемый в диалоговом окне.
В главном окне создается экземпляр диалогового окна, передается ему модель представления и отображается диалог. Результат диалога возвращается обратно вызывающему в исходное сообщение.
Это выглядит примерно так:
В вашей модели просмотра:
DialogViewModel viewModel = new DialogViewModel(...);
ShowDialogMessage message = new ShowDialogMessage(viewModel);
_messenger.Broadcast(message);
if (message.Result == true)
{
...
}
В главном окне codebehind:
void RecieveShowDialogMessage(ShowDialogMessage message)
{
DialogWindow w = new DialogWindow();
w.DataContext = message.ViewModel;
message.Result = w.ShowDialog();
}
Надеюсь, этого достаточно, чтобы дать вам идею...
Ответ 3
Как я понял ваш комментарий выше, вопрос заключается не столько в том, чтобы показывать диалоги, как об их скрытии. Существует два способа решить эту проблему:
-
Используйте стандартное диалоговое окно для реализации представления. Это потребует наличия слабосвязанного способа связи между View и ViewModel, чтобы ViewModel мог уведомить View, который он закрыл, без ссылки на представление.
Существует несколько фреймворков, которые позволили бы это сделать - агрегаторы событий Prism были бы одним из них. В этом случае View будет подписаться на событие (скажем, MyDialogResultValidated), и после получения события он установит диалоговое окно DialogResult. ViewModel (в SaveCommand) запустит событие, если проверка прошла успешно.
-
Не используйте стандартное диалоговое окно для реализации представления. Это потребует наличия наложения, которое эффективно эмулирует модальность.
В этом случае видимость представления и наложения будет привязана к свойству ViewModel IsVisible, которое будет установлено соответственно реализацией SaveCommand или когда ViewModel должен показать представление.
Первый подход потребует наличия кода с кодом в коде, требуется добавить глобальные события (события) и (возможно) меньше MVVM-ish. Второй подход потребует внедрения (или использования какой-либо другой реализации) оверлея, но не потребует наличия какого-либо кода в кодировке, не потребует наличия глобальных событий (событий) и (возможно) более MVVM-ish,
Ответ 4
Я согласен, что использование сервиса для отображения диалога в соответствии с шаблоном MVVM является самым простым решением. Но я также спросил себя, есть ли 3 сборки в моей модели Model, ViewModel, View и в соответствии с сборкой шаблонов MVVM. В ViewModel есть ссылка на Model и View на Model и ViewModel, где я должен разместить класс DialogService? Если я поместил его в сборку ViewModel, у меня нет шансов создать экземпляр DialogView; с другой стороны, если я поместил DialogService в сборку "Просмотр", как я должен ввести ее в мой класс ViewModel?
Итак, я бы рекомендовал посмотреть Расширенные сценарии MVVM с Призма Часть: Использование объектов запроса на взаимодействие
В качестве примера такого подхода:
DialogViewModelBase
public abstract class DialogViewModelBase : ViewModelBase
{
private ICommand _ok;
public ICommand Ok
{
get { return _ok ?? (_ok = new DelegateCommand(OkExecute, CanOkExecute)); }
}
protected virtual bool CanOkExecute()
{
return true;
}
protected virtual void OkExecute()
{
_isSaved = true;
Close = true;
}
private ICommand _cancel;
public ICommand Cancel
{
get
{
return _cancel ?? (_cancel = new DelegateCommand(CancelExecute, CanCancelExecute));
}
}
protected virtual bool CanCancelExecute()
{
return true;
}
protected virtual void CancelExecute()
{
Close = true;
}
private bool _isSaved = false;
public bool IsSaved
{
get { return _isSaved; }
}
private bool _close = false;
public bool Close
{
get { return _close; }
set
{
_close = value;
RaisePropertyChanged(() => Close);
}
}
}
CreateUserStoryViewModel:
public class CreateUserStoryViewModel : DialogViewModelBase
{
private string _name = String.Empty;
public string Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChanged(() => Name);
}
}
}
CreateUserStoryRequest
private InteractionRequest<Notification> _createUserStoryRequest;
public InteractionRequest<Notification> CreateUserStoryRequest
{
get
{
return _createUserStoryRequest ?? (_createUserStoryRequest = new InteractionRequest<Notification>());
}
}
Команда CreateUserStory
private void CreateUserStoryExecute()
{
CreateUserStoryRequest.Raise(new Notification()
{
Content = new CreateUserStoryViewModel(),
Title = "Create User Story"
},
notification =>
{
CreateUserStoryViewModel createUserStoryViewModel =
(CreateUserStoryViewModel)notification.Content;
if (createUserStoryViewModel.IsSaved)
{
_domainContext.CreateUserStory(
new UserStory(){ Name = createUserStoryViewModel.Name, });
}
});
}
XAML:
<!--where xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ir="clr-namespace:Microsoft.Practices.Prism.Interactivity.InteractionRequest;assembly=Microsoft.Practices.Prism.Interactivity"-->
<i:Interaction.Triggers>
<ir:InteractionRequestTrigger SourceObject="{Binding CreateUserStoryRequest}">
<ir:PopupChildWindowAction>
<ir:PopupChildWindowAction.ChildWindow>
<view:CreateUserStory />
</ir:PopupChildWindowAction.ChildWindow>
</ir:PopupChildWindowAction>
</ir:InteractionRequestTrigger>
</i:Interaction.Triggers>
Ответ 5
Вам может быть интересно следующее приложение-образец:
http://compositeextensions.codeplex.com
Он использует Prism2 с шаблоном PresentationModel (aka MVVM). Пример приложения содержит модальный диалог.
Ответ 6
Это не Prism, но эта демоверсия MVVM имеет Диалог опций, который полностью MVVM.