如何在不违反MVVM模式规则的情况下在WPF中打开/关闭新窗口?
我只是想模仿ms office outlook的登录模块.
我已经阅读过这篇文章,但传递参数时出错confirmation
我目前正在使用棱镜5.0.
幸运的是,Prism 5.0(我也假设6.0,还没有使用它),有一个类InteractionRequest
,你可以使用代码来提出交互请求.
交互请求基本上是一个窗口,它要求用户执行某个操作,并使用用户决策/操作调用回调(如果必要或需要).
public class ShellViewModel : BindableBase { private readonly IRegionManager regionManager; public ShellViewModel(IRegionManager regionManager) { if (regionManager == null) throw new ArgumentNullException("regionManager"); this.regionManager = regionManager; this.OptionSettingConfirmationRequest = new InteractionRequest(); openConnectionOptionsCommand = new DelegateCommand(RaiseConnectionOptionsRequest); } public InteractionRequest OptionSettingConfirmationRequest { get; private set; } private readonly ICommand openConnectionOptionsCommand; public ICommand OpenConnectionOptionsCommand { get { return openConnectionOptionsCommand; } } private void RaiseConnectionOptionsRequest() { this.OptionSettingConfirmationRequest.Raise(new Confirmation { Title = "Options not saved. Do you wish to save?" }, OnConnectionOptionsResponse); } protected virtual void OnConnectionOptionsResponse(IConfirmation context) { if(context.Confirmed) { // save it } // otherwise do nothing } }
在XAML中你会做类似的事情
我使用了自己的实现PopupWindowAction
(参见github项目页面的实现)调用LazyPopupWindowAction
,它将实例化嵌入的ConnectionSettingsView
View on click.如果您不关心您的视图只被实例化一次,请随意使用PopupWindowAction
,然后它将与包含该操作的视图同时实例化.
它基本上是复制和粘贴,从我的一个项目切割一些无用的线条.我使用IConfirmation
和INotification
接口而不是具体的实现.
XAML用 PopupWindowAction
命名空间声明
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:pi="clr-namespace:Microsoft.Practices.Prism.Interactivity;assembly=Microsoft.Practices.Prism.Interactivity" xmlns:pit="clr-namespace:Microsoft.Practices.Prism.Interactivity.InteractionRequest;assembly=Microsoft.Practices.Prism.Interactivity" xmlns:pie="clr-namespace:MyProject.UI.Prism.Interactivity;assembly=MyProject.UI"
更新:
由于人们不断询问LazyPopupWindowAction
,我将源代码放在GitHub Gist中.基本上它是基于PopupWindowAction
Prims 5(对于Prism来说,尚未用Prism 6进行测试,可能无法正常调整)并完全相同,但也增加了Region和Navigation支持窗口,我在我的应用程序中需要的东西.
我不喜欢默认实现的一件事是,视图和它的viewmodel将在Shell被实例化的同时实例化,并且ViewModel保持在它的状态,当你关闭它时(它实际上只是隐藏).
更新
是什么让我得出另一个答案是无法在我使用Prism 6的项目中应用已接受的答案,
但在提出原始答案(见下文)并在评论中讨论之后,我发现核心问题是:该棱镜6改变了一些类的命名空间,这在公认的答案是仍然存在使用的所有类棱镜6,但在另一个DLL和命名空间
因此,如果您使用的棱镜6,你可以申请使用这些修改的接受的答案
首先替换那些名字
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:pi="clr-namespace:Microsoft.Practices.Prism.Interactivity;assembly=Microsoft.Practices.Prism.Interactivity" xmlns:pit="clr-namespace:Microsoft.Practices.Prism.Interactivity.InteractionRequest;assembly=Microsoft.Practices.Prism.Interactivity"
具有以下命名空间
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:prism="http://prismlibrary.com/"
第二次更新XAML如下
注意1
确保您使用的视图(在上面的示例中
)不是窗口,否则您将收到异常.
注2: 只有在使用Prism 6时才
需要进行这些修改.因为(正如我在下面的原始答案中所说),Prism 6中不推荐接受答案使用的dll .
注3
:确保引用Prism.Wpf
dll,可以从Nuget下载.
实际上你在你的问题中引用的文章非常有用(至少对我而言),并且它不会崩溃.
我会尝试总结那篇文章.
视图模型
public class ViewModel : BindableBase { public ViewModel() { _showWindowCommand = new DelegateCommand(ShowWindow); _interactionRequest = new InteractionRequest(); } private readonly DelegateCommand _showWindowCommand; private InteractionRequest _interactionRequest; public ICommand ShowWindowCommand { get { return _showWindowCommand; } } public IInteractionRequest InteractionRequest { get { return _interactionRequest; } } private void ShowWindow() { _interactionRequest.Raise( new Confirmation(), OnWindowClosed); } private void OnWindowClosed(Confirmation confirmation) { if (confirmation.Confirmed) { //perform the confirmed action... } else { } } }
XAML
并且您将需要使用这些名称空间
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:local="clr-namespace:The namespace which contains the ShowWindowAction">
ActionTrigger
using System; using Prism.Interactivity.InteractionRequest; using System.Windows.Interactivity; using System.Windows; public class ShowWindowAction : TriggerAction{ protected override void Invoke(object parameter) { InteractionRequestedEventArgs args = parameter as InteractionRequestedEventArgs; if (args != null) { Confirmation confirmation = args.Context as Confirmation; if (confirmation != null) { // Replace ParametersWindow with your own window. ParametersWindow window = new ParametersWindow(); EventHandler closeHandler = null; closeHandler = (sender, e) => { window.Closed -= closeHandler; args.Callback(); }; window.Closed += closeHandler; window.Show(); } } } }
说明
你需要Prism.Core
和Prism.Wpf
dll(至少)使这段代码有效.
ShowWindow
方法,将触发Invoke
方法ShowWindowAction
,这将真正显示窗口.
你可以处理窗口的关闭OnWindowClosed
,我们将它作为回调传递给ShowWindowAction
类,当窗口真正关闭时我们从那里调用它.