WPF MVVM 对话框示例
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1667888/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF MVVM dialog example
提问by Oll
Does anyone have any examples of showing a window dialog using MVVM (Prism)? - for example a configuration settings window when a command is executed.
有没有人有使用 MVVM (Prism) 显示窗口对话框的示例?- 例如,执行命令时的配置设置窗口。
All of the examples I've seen use the mediator pattern which is fine, but they also all have a reference to the view in the view model which is not ideal (we're using DataTemplates)
我见过的所有示例都使用中介者模式,这很好,但它们也都引用了不理想的视图模型中的视图(我们使用的是 DataTemplates)
Thanks
谢谢
回答by Cameron MacFarland
I would use a service to display the dialog. The service can then also link views with viewmodels.
我会使用服务来显示对话框。然后,该服务还可以将视图与视图模型链接起来。
public interface IDialogService {
void RegisterView<TView, TViewModel>() where TViewModel:IDialogViewModel;
bool? ShowDialog(IDialogViewModel viewModel);
}
public interface IDialogViewModel {
bool CanClose();
void Close();
}
RegisterView
just links the view type with the ViewModel type. You can set up these links in the module initialization. This is simpler than trying to get modules to register datatemplates in the top layer of your application.
RegisterView
只是将视图类型与 ViewModel 类型联系起来。您可以在模块初始化中设置这些链接。这比尝试让模块在应用程序的顶层注册数据模板更简单。
ShowDialog
Shows the ViewModel you want to display. It returns true, false and null for close just like the Window.ShowDialog
method. The implementation just creates a new view of type TView
from your container, hooks it up to the provided ViewModel, and shows it.
ShowDialog
显示您要显示的 ViewModel。就像Window.ShowDialog
方法一样,它为 close 返回 true、false 和 null 。该实现只是TView
从您的容器创建一个新的类型视图,将其连接到提供的 ViewModel,并显示它。
IDialogViewModel
provides a mechanism for the ViewModel to do verification and cancel the closing of the dialog.
IDialogViewModel
为 ViewModel 提供了一种机制来进行验证和取消对话框的关闭。
I have a standard dialog window, with a content control in it. When ShowDialog
is called it creates a new standard dialog, adds the view to the content control, hooks up the ViewModel and displays it. The standard dialog already has [OK] and [Cancel] buttons with the appropriate logic to call the right methods from IDialogViewModel
.
我有一个标准的对话窗口,里面有一个内容控件。当ShowDialog
被调用时,它会创建一个新的标准对话框,将视图添加到内容控件,连接 ViewModel 并显示它。标准对话框已经有 [OK] 和 [Cancel] 按钮,带有适当的逻辑来调用正确的方法IDialogViewModel
。
回答by Grokys
The way I do this is using the mediator pattern also. When the ViewModel wants to show a dialog, it sends a message which is picked up by the application's main window. The message contains an instance of the ViewModel used by the dialog.
我这样做的方式也是使用中介者模式。当 ViewModel 想要显示一个对话框时,它会发送一条消息,该消息由应用程序的主窗口接收。该消息包含对话框使用的 ViewModel 的一个实例。
The main window then constructs an instance of the dialog window, passes the view model to it and shows the dialog. The result of the dialog is passed back to the caller in the original message.
然后主窗口构造对话窗口的实例,将视图模型传递给它并显示对话框。对话的结果在原始消息中传回给调用者。
It looks something like this:
它看起来像这样:
In your view model:
在您的视图模型中:
DialogViewModel viewModel = new DialogViewModel(...);
ShowDialogMessage message = new ShowDialogMessage(viewModel);
_messenger.Broadcast(message);
if (message.Result == true)
{
...
}
In the main window codebehind:
在主窗口代码隐藏中:
void RecieveShowDialogMessage(ShowDialogMessage message)
{
DialogWindow w = new DialogWindow();
w.DataContext = message.ViewModel;
message.Result = w.ShowDialog();
}
I hope this is enough to give you the idea...
我希望这足以给你这个想法......
回答by Vladimir Dorokhov
I'm agreed, that using service to display dialog according to MVVM pattern is the most simple solution. But, I also asked myself, if there are 3 assemblies in my project Model, ViewModel, View and according to MVVM pattern assembly ViewModel has a reference to Model, and View to both Model and ViewModel where should I place DialogService class? If I will place one in the ViewModel assembly - I have no chances to create DialogView instance; on the other hand, if I will place DialogService in the View assembly, how I should inject it in my ViewModel class?
我同意,使用服务根据 MVVM 模式显示对话框是最简单的解决方案。但是,我也问自己,如果我的项目 Model、ViewModel、View 中有 3 个程序集,并且根据 MVVM 模式程序集 ViewModel 有对 Model 的引用,以及对 Model 和 ViewModel 的 View 我应该在哪里放置 DialogService 类?如果我将在 ViewModel 程序集中放置一个 - 我没有机会创建 DialogView 实例;另一方面,如果我将 DialogService 放在 View 程序集中,我应该如何将它注入我的 ViewModel 类?
So, I would recoment look at Advanced MVVM scenarios with PrismPart: Using Interaction Request Objects
所以,我会推荐使用 Prism Part: Using Interaction Request Objects 来看看Advanced MVVM 场景
As example of this approach:
作为这种方法的示例:
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 Command
创建用户故事命令
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:
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>
回答by PL.
As I understood your comment above, the question is not so much about showing the dialogs as about hiding them. There are two ways to solve this problem:
据我了解您在上面的评论,问题与其说是显示对话框,不如说是隐藏它们。有两种方法可以解决这个问题:
Use standard dialog window to implement the view. This would require to have a loosely coupled way of communication between View and ViewModel so that ViewModel can notify the View that it's ok to close without having a reference to a view.
There are multiple frameworks exist that would allow to do it - Prism's event aggregators would be one of them. In this scenario View would subscribe to an event (say, MyDialogResultValidated), and on receiving the event it would set the DialogResult accrodingly. ViewModel (in its SaveCommand) would fire the event if validation was successful.
Don't use standard dialog window to implement the view. This would require to have an overlay that would effectively emulate modality.
In this scenario the Visibility of the View and of the overlay will be bound ViewModel's IsVisible property that would be set accordingly by SaveCommand implementation, or whenever ViewModel needs to show the View.
使用标准对话窗口来实现视图。这将需要在 View 和 ViewModel 之间采用松散耦合的通信方式,以便 ViewModel 可以通知 View 可以在没有引用视图的情况下关闭。
有多种框架允许这样做——Prism 的事件聚合器就是其中之一。在这种情况下,View 将订阅一个事件(例如 MyDialogResultValidated),并且在接收到该事件时,它将相应地设置 DialogResult。如果验证成功,ViewModel(在其 SaveCommand 中)将触发该事件。
不要使用标准对话框窗口来实现视图。这需要有一个可以有效模拟模态的叠加层。
在这种情况下,视图和覆盖层的可见性将绑定 ViewModel 的 IsVisible 属性,该属性将由 SaveCommand 实现进行相应设置,或者在 ViewModel 需要显示视图时进行设置。
The first approach would require having a bit of code in code-behind, requires adding global event(s), and (arguably) is less MVVM-ish. The second approach would require implementing (or using someone else's implementation) of the overlay, but won't require having any code in code-behind, won't require having global event(s), and is (arguable) more MVVM-ish.
第一种方法需要在代码隐藏中添加一些代码,需要添加全局事件,并且(可以说)不太像 MVVM。第二种方法需要实现(或使用其他人的实现)覆盖,但不需要在代码隐藏中包含任何代码,不需要全局事件,并且(有争议的)更像 MVVM .
回答by jbe
You might be interested in the following sample application:
您可能对以下示例应用程序感兴趣:
http://compositeextensions.codeplex.com
http://compositeextensions.codeplex.com
It uses Prism2 with the PresentationModel (aka MVVM) pattern. The sample application contains a modal dialog.
它使用 Prism2 和 PresentationModel(又名 MVVM)模式。示例应用程序包含一个模式对话框。