我已经阅读了this article,但是在传递参数
confirmation
时出现错误。我目前正在使用prism 5.0。
confirmation
时出现错误。InteractionRequest<T>
的类,您可以从代码中使用它来发出交互请求。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<IConfirmation>();
openConnectionOptionsCommand = new DelegateCommand(RaiseConnectionOptionsRequest);
}
public InteractionRequest<IConfirmation> 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中,您可以这样做:<Button Content="Options" Command="{Binding OpenConnectionOptionsCommand}">
<i:Interaction.Triggers>
<pit:InteractionRequestTrigger SourceObject="{Binding OptionSettingConfirmationRequest, Mode=OneWay}" >
<pie:LazyPopupWindowAction RegionName="ConnectionSettings"
NavigationUri="ConnectionSettingsView" IsModal="True" />
</pit:InteractionRequestTrigger>
</i:Interaction.Triggers>
</Button>
我使用了自己实现的PopupWindowAction
(请看GitHub项目页面获取其实现),名为LazyPopupWindowAction
,点击时会实例化嵌入的ConnectionSettingsView
视图。如果您不在意视图只被实例化一次,可以随意使用PopupWindowAction
,此时它将与包含该操作的视图同时被实例化。
这基本上就是从我的某个项目中拷贝并削减了一些无用行。我使用了IConfirmation
和INotification
接口而非具体实现。
XAML中使用PopupWindowAction
<Button Content="Options" Command="{Binding OpenConnectionOptionsCommand}">
<i:Interaction.Triggers>
<pit:InteractionRequestTrigger SourceObject="{Binding OptionSettingConfirmationRequest, Mode=OneWay}" >
<pi:PopupWindowAction>
<pi:PopupWindowAction.WindowContent>
<views:CustomPopupView />
</pi:PopupWindowAction.WindowContent>
</pi:PopupWindowAction>
</pit:InteractionRequestTrigger>
</i:Interaction.Triggers>
</Button>
命名空间声明
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中。基本上它是基于Prism 5的PopupWindowAction
(针对Prism而言,尚未使用Prism 6进行测试,可能需要调整才能正常工作),并且执行完全相同的操作,但还添加了区域和导航支持以及打开的窗口,这是我在应用程序中所需要的。
我不喜欢默认实现的一件事是,在Shell实例化时视图及其视图模型将同时实例化,当你关闭它时(实际上只是隐藏了它),视图模型仍然保持原状。
本回答仅适用于 Prism 7,
如果您使用之前的版本(6及以下),
那么本回答不适用于您
Prism 7对打开新窗口的方式进行了彻底的改变。
如果您想阅读官方文档,请查看此处。
此外,还有一段Youtube视频由Prism库的作者解释这个思路。
Prism 7引入了DialogService
,一种全新的打开新窗口的方式。
<UserControl x:Class="YourUserControlName"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<Grid>
</Grid>
</UserControl>
IDialogAware
接口。public class BaseDialogViewModel : IDialogAware
{
public string Title { get; }
public event Action<IDialogResult> RequestClose;
public virtual void RaiseRequestClose(IDialogResult dialogResult)
{
RequestClose?.Invoke(dialogResult);
}
public virtual bool CanCloseDialog()
{
return true;
}
public virtual void OnDialogClosed()
{
}
public virtual void OnDialogOpened(IDialogParameters parameters)
{
}
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
// replace 'YourUserControlName' with the class of the view which you created in setp 1
containerRegistry.RegisterDialog<YourUserControlName>();
}
_dialogService.ShowDialog(nameof(YourUserControlName), new DialogParameters(), action);
_dialogService
是IDialogService
类型的,它被注入到视图模型中,在使用时会用到它。例如:public MainViewModel(IDialogService dialogService)
{
this._dialogService = dialogService;
}
所有先前的步骤都是为了显示窗口所必需的。
还有一些其他可选步骤(如果需要)
prism:Dialog.WindowStyle
xaml元素来指定窗口的属性。<UserControl x:Class="YourUserControlName"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<prism:Dialog.WindowStyle>
<Style TargetType="Window">
<Setter Property="prism:Dialog.WindowStartupLocation" Value="CenterScreen" />
<Setter Property="ResizeMode" Value="NoResize"/>
<Setter Property="ShowInTaskbar" Value="False"/>
<Setter Property="WindowState" Value="Maximized"/>
</Style>
</prism:Dialog.WindowStyle>
<Grid>
</Grid>
</UserControl>
public static class DialogServiceExtensions
{
public static void ShowWindowTest(this IDialogService dialogService, Action<IDialogResult> action)
{
dialogService.ShowDialog(nameof(WindowTestView), new DialogParameters(), action);
}
}
Prism文档建议这样做,但不要求。
如果您想要一个新的Prism 7 WPF应用程序的样板设置,并带有.NET Core 3.1,则可以查看此Github存储库。
它包含上述设置和许多其他有用的功能,用于启动WPF Prism应用程序。
免责声明:我是该存储库的作者
你是否使用Prism 7?
如果是,则立即停止阅读并转到下面的Prism 7答案
如果不是,则继续阅读
更新
我提供另一个答案的原因是在我的项目中,使用了Prism 6,无法应用已接受的答案。但在放置原始答案(请参见下文)并在评论中讨论后,我发现核心问题是:Prism 6更改了一些类的名称空间,所有已在接受的答案中使用的类仍然存在于Prism 6中,但在其他dll和命名空间中。因此,如果您正在使用Prism 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/"
<Button Content="Options" Command="{Binding OpenConnectionOptionsCommand}">
<i:Interaction.Triggers>
<prism:InteractionRequestTrigger SourceObject="{Binding OptionSettingConfirmationRequest, Mode=OneWay}" >
<prism:PopupWindowAction>
<prism:PopupWindowAction.WindowContent>
<views:CustomPopupView />
</prism:PopupWindowAction.WindowContent>
</prism:PopupWindowAction>
</prism:InteractionRequestTrigger>
</i:Interaction.Triggers>
</Button>
注意 1
确保你使用的视图(在上面的示例中为<views:CustomPopupWindow>
)不是一个窗口,否则会收到异常。
注意 2
只有在使用Prism 6时才需要进行这些修改。因为(如下面的原始答案中所说),被接受的答案使用的dll在Prism 6中已被弃用。
注意 3
确保您正在引用Prism.Wpf
dll,该dll可以从Nuget下载。
实际上,你问题中引用的文章对我很有帮助,它没有崩溃。
我会尝试总结那篇文章。
ViewModel(视图模型)
public class ViewModel : BindableBase
{
public ViewModel()
{
_showWindowCommand = new DelegateCommand(ShowWindow);
_interactionRequest = new InteractionRequest<Confirmation>();
}
private readonly DelegateCommand _showWindowCommand;
private InteractionRequest<Confirmation> _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
<Button Command="{Binding ShowWindowCommand}" Content="Show Window" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Raised" SourceObject="{Binding InteractionRequest}">
<i:EventTrigger.Actions>
<local:ShowWindowAction></local:ShowWindowAction>
</i:EventTrigger.Actions>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
你需要使用这些命名空间
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<FrameworkElement>
{
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
dlls。ShowWindow
方法将触发ShowWindowAction
的Invoke
方法,从而真正显示窗口。OnWindowClosed
中处理窗口的关闭,我们将其作为回调传递给ShowWindowAction
类,在那里关闭窗口时调用它。PopupWindowAction
在Prism 6中仍然存在(https://github.com/PrismLibrary/Prism/blob/master/Source/Wpf/Prism.Wpf/Interactivity/PopupWindowAction.cs),而且`IConfirmation`和`Confirmation`类在两个框架中仍然存在。除了Prism5当时仍由MS维护,而Prims6现在是社区的,对这些类的使用没有改变。除非您需要`PopupWindowAction`不提供的内容(例如延迟加载,我需要每次调用时都有新的视图和视图模型),否则不需要自己编写`TriggerAction`。 - TsengActionTrigger
也许对其他人有帮助,我还使用了一个 i:EventTrigger
而不是 InteractionRequestTrigger
,但总的来说,我们的答案非常接近。 - Hakan FıstıkShellViewModel
是什么?它是指 MainWindowViewModel
吗?InteractionRequest
应该放在哪里,是在 MainWindow.xaml
中吗? - Shimmy Weitzhandler
Button
类的Label="Options"
,因为Button
没有这样的属性。您是指应该使用Content="Options"
吗? - Hakan FıstıkContent='"Options"
。我把大部分代码从当时正在工作的项目中复制过来并进行了改装。我使用的是RibbonControlsLibrary和它的RibbonSplitButton
,它使用Label
而不是Content
来描述。 - TsengShellViewModel
之外的其他地方引发交互? - Shimmy Weitzhandler