【发布时间】:2010-12-12 16:17:17
【问题描述】:
有没有人有任何使用 MVVM (Prism) 显示窗口对话框的示例? - 例如执行命令时的配置设置窗口。
我见过的所有示例都使用中介者模式,这很好,但它们也都引用了视图模型中的视图,这并不理想(我们正在使用 DataTemplates)
谢谢
【问题讨论】:
标签: wpf mvvm prism prism-2 mediator
有没有人有任何使用 MVVM (Prism) 显示窗口对话框的示例? - 例如执行命令时的配置设置窗口。
我见过的所有示例都使用中介者模式,这很好,但它们也都引用了视图模型中的视图,这并不理想(我们正在使用 DataTemplates)
谢谢
【问题讨论】:
标签: wpf mvvm prism prism-2 mediator
我会使用服务来显示对话框。该服务还可以将视图与视图模型链接。
public interface IDialogService {
void RegisterView<TView, TViewModel>() where TViewModel:IDialogViewModel;
bool? ShowDialog(IDialogViewModel viewModel);
}
public interface IDialogViewModel {
bool CanClose();
void Close();
}
RegisterView 只是将视图类型与 ViewModel 类型链接起来。您可以在模块初始化中设置这些链接。这比尝试让模块在应用程序的顶层注册数据模板更简单。
ShowDialog 显示您要显示的 ViewModel。就像 Window.ShowDialog 方法一样,它返回 true、false 和 null 来关闭。该实现只是从您的容器中创建一个 TView 类型的新视图,将其连接到提供的 ViewModel 并显示它。
IDialogViewModel 为 ViewModel 提供了一种机制来进行验证并取消对话框的关闭。
我有一个标准的对话窗口,里面有一个内容控件。当ShowDialog 被调用时,它会创建一个新的标准对话框,将视图添加到内容控件,连接 ViewModel 并显示它。标准对话框已经有 [OK] 和 [Cancel] 按钮,它们具有适当的逻辑,可以从 IDialogViewModel 调用正确的方法。
【讨论】:
ShowDialog 的代码实现只会找到它需要显示的视图,然后在该视图上调用ShowDialog,并将结果传回。
我这样做的方式也是使用中介模式。当 ViewModel 想要显示一个对话框时,它会发送一条消息,该消息由应用程序的主窗口接收。该消息包含对话框使用的 ViewModel 实例。
然后主窗口构造对话框窗口的实例,将视图模型传递给它并显示对话框。对话的结果在原始消息中传回给调用者。
看起来像这样:
在您的视图模型中:
DialogViewModel viewModel = new DialogViewModel(...);
ShowDialogMessage message = new ShowDialogMessage(viewModel);
_messenger.Broadcast(message);
if (message.Result == true)
{
...
}
在主窗口代码隐藏中:
void RecieveShowDialogMessage(ShowDialogMessage message)
{
DialogWindow w = new DialogWindow();
w.DataContext = message.ViewModel;
message.Result = w.ShowDialog();
}
我希望这足以给你这个想法......
【讨论】:
我同意,根据 MVVM 模式使用服务显示对话框是最简单的解决方案。但是,我也问自己,如果我的项目中有 3 个程序集 Model、ViewModel、View 和根据 MVVM 模式的程序集 ViewModel 有对 Model 的引用,而 View 对 Model 和 ViewModel 我应该在哪里放置 DialogService 类?如果我将在 ViewModel 程序集中放置一个 - 我没有机会创建 DialogView 实例;另一方面,如果我将 DialogService 放在 View 程序集中,我应该如何将它注入到我的 ViewModel 类中?
所以,我会推荐看看Advanced MVVM scenarios with Prism 部分:使用交互请求对象
作为这种方法的示例:
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);
}
}
}
创建用户故事视图模型:
public class CreateUserStoryViewModel : DialogViewModelBase
{
private string _name = String.Empty;
public string Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChanged(() => Name);
}
}
}
创建用户故事请求
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>
【讨论】:
据我了解您在上面的评论,问题不在于显示对话框,而在于隐藏它们。有两种方法可以解决这个问题:
使用标准对话窗口来实现视图。这需要在 View 和 ViewModel 之间有一种松散耦合的通信方式,以便 ViewModel 可以通知 View 可以在不引用视图的情况下关闭。
存在多个允许这样做的框架 - Prism 的事件聚合器就是其中之一。在这种情况下,View 将订阅一个事件(例如,MyDialogResultValidated),并且在接收到该事件时,它将相应地设置 DialogResult。如果验证成功,ViewModel(在其 SaveCommand 中)将触发该事件。
不要使用标准的对话窗口来实现视图。这需要有一个可以有效模拟模态的叠加层。
在这种情况下,视图和叠加层的可见性将绑定 ViewModel 的 IsVisible 属性,该属性将由 SaveCommand 实现相应地设置,或者在 ViewModel 需要显示视图时进行设置。
第一种方法需要在代码隐藏中添加一些代码,需要添加全局事件,并且(可以说)更少 MVVM-ish。第二种方法需要实现(或使用其他人的实现)覆盖,但不需要在代码隐藏中包含任何代码,不需要全局事件,并且(有争议的)更 MVVM-ish .
【讨论】:
您可能对以下示例应用程序感兴趣:
http://compositeextensions.codeplex.com
它将 Prism2 与 PresentationModel(又名 MVVM)模式一起使用。示例应用程序包含一个模式对话框。
【讨论】:
这不是 Prism,但这个 MVVM demo 有一个完全是 MVVM 的选项对话框。
【讨论】: