RegionAdapter负责创建区域,并将区域与控件绑定,以及将自定义的视图到传入到指定的区域。
当需要将没有某些没有适配器的控件作为区域的时候,我们就必须要通过继承RegionAdapterBase<>自定义对应的适配器。下面是自定义适配器的流程,并以StackPanel控件定义区域为例:
继承RegionAdapterBase类实现适配器的自定义
// An highlighted block
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace BlankApp2
{
public class StackAdapter : RegionAdapterBase<StackPanel>
{
public StackAdapter(IRegionBehaviorFactory regionBehaviorFactory) : base(regionBehaviorFactory)
{
}
protected override void Adapt(IRegion region, StackPanel regionTarget)
{
region.Views.CollectionChanged += (s, e) =>
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
foreach (UIElement element in e.NewItems)
{
regionTarget.Children.Add(element);
}
}
};
}
// 下面方法可以创建返回三种区域类型:
// SingleActiveRegion:一次最多允许一个活动视图
// AllActiveRegion:使其中的所有视图保持活动状态的区域。不允许停用视图。
// Region
protected override IRegion CreateRegion()
{
return new Region();
}
}
}
区域适配器类与对应控件之间的注册:
// An highlighted block
using BlankApp2.Views;
using Prism.Regions;
using System.Windows;
using System.Windows.Controls;
namespace BlankApp2
{
public partial class App
{
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
}
// 重写下面函数完成适配器的注册
protected override void ConfigureRegionAdapterMappings(RegionAdapterMappings regionAdapterMappings)
{
base.ConfigureRegionAdapterMappings(regionAdapterMappings);
regionAdapterMappings.RegisterMapping(typeof(StackPanel), Container.Resolve<StackAdapter>());
}
}
}
视图注入View injection
将视图注入到对应的区域中(view discovery和view injection两种方法)
// View discovery first methord
regionManager.RegisterViewWithRegion("MainRegion", typeof(EmployeeView));
使用view discovery方法将视图注入至对应区域具体代码如下所示:
using Prism.Ioc;
using Prism.Regions;
using System.Windows;
namespace BlankApp3.Views
{
public partial class MainWindow : Window
{
public MainWindow(IRegionManager regionManager)
{
InitializeComponent();
regionManager.RegisterViewWithRegion("ContentRegion", typeof(UserControl1));
regionManager.RegisterViewWithRegion("StackRegion", typeof(UserControl2));
}
}
}
View injection方法实现视图注入至Region
IRegion region = regionManager.Regions["MainRegion"]; // 从区域管理器获取区域
var ordersView = container.Resolve<OrdersView>(); // 从视图容器中获取视图
region.Add(ordersView, "OrdersView"); // 将视图添加到对应的区域中
region.Activate(ordersView); // 激活显示视图在region中
具体案例代码如下所示:
using Prism.Ioc;
using Prism.Regions;
using System.Windows;
namespace BlankApp3.Views
{
///
/// Interaction logic for MainWindow.xaml
///
public partial class MainWindow : Window
{
IContainerExtension _container;
IRegionManager _regionManager;
public MainWindow(IContainerExtension container, IRegionManager regionManager)
{
InitializeComponent();
_container = container;
_regionManager = regionManager;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var view = _container.Resolve<UserControl1>();
IRegion region = _regionManager.Regions["ContentRegion"];
region.Add(view);
region.Activate(view);
var view1 = _container.Resolve<UserControl2>();
IRegion region1 = _regionManager.Regions["StackRegion"];
region1.Add(view1);
region1.Activate(view1);
}
}
}
两种视图注入的使用场景(第一种自动注入,第二种可以实现手动控制注入)
使用 view discovery的场景:
(1)需要视图能够被自动加载到区域.
(2)单个视图实例被加载到区域。(该方式会加载全部符合指定视图类型的视图实例)
使用 view injection 的场景:
(1)应用需要使用Navigation APIs.
(2)需要在编程控制中能够精确的指定视图的创建与显示, 或者需要删除一个区域中的某个视图;
(3)需要在一个region中展示同一个view的多个实例, 并且每一个视图实例都绑定在不同的数据上.
(4)需要控制将视图添加到区域的哪个实例。例如需要将客户详细信息的视图添加到客户详细信息的指定region中。
将一个应用程序按照最大不相关分离成多个低耦合的功能单元,这些单元由view、viewmodel、logic等部分组成,可以相对于其他模块独立运行和测试。
Prism提供了了Module的模板(默认使用view discovery的方式注入视图)
// 下面的方法可以使用view inject或者是视图导航的方式将视图注入。
namespace ModuleA
{
public class ModuleAModule : IModule
{
// 该方法通常用于将视图注入至区域中
public void OnInitialized(IContainerProvider containerProvider)
{
var regionManager = containerProvider.Resolve<IRegionManager>();
regionManager.RegisterViewWithRegion("ContentRegion", typeof(ViewA));
}
// 该方法通常用于实现view与对应viewmodel的关联,以及可以将视图添加至导航管理器中
public void RegisterTypes(IContainerRegistry containerRegistry)
{
}
}
}
将Module导入到应用项目中通常有5种方法
// 在App.xaml.cs中使用代码导入Module
namespace Modules
{
public partial class App : PrismApplication
{
protected override Window CreateShell(){
return Container.Resolve<MainWindow>();}
protected override void RegisterTypes(IContainerRegistry containerRegistry){}
// 导入对应的模块至应用中
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog){
moduleCatalog.AddModule<ModuleA.ModuleAModule>(); }
}
}
// 使用手动方式将Module加载至应用
using Prism.Modularity;
using System.Windows;
namespace Modules.Views
{
public partial class MainWindow : Window
{
IModuleManager _moduleManager;
public MainWindow(IModuleManager moduleManager)
{
InitializeComponent();
_moduleManager = moduleManager;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
_moduleManager.LoadModule("ModuleAModule");
}
}
}
在prism应用中view是如何与viewmodle相互关联的呢?默认情况下在XAML代码中会有如下代码。该方法会更具默认的命名规则将view与viewmodel相互关联。(viewA与viewAViewModel)
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
也可以重写ConfigureViewModelLocator方法并使用ViewModelLocator将view和其对应的viewmodel联系在一起,ViewModelLocator使用标准的名称约定使得view的上下文被关联到viewmodel的一个实例上。
// 1. Type/Type模式
ViewModelLocationProvider.Register(typeof(MainWindow).ToString(),typeof(CustomViewModel));
// 2. Type/Factory模式
ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), () => Container.Resolve());
// 3. Generic Factory
ViewModelLocationProvider.Register(() => Container.Resolve());
// 4.Generic Type
ViewModelLocationProvider.Register();
具体的案例代码如下所示:
using BlankApp3.ViewModels;
using BlankApp3.Views;
using Prism.Ioc;
using Prism.Mvvm;
using Prism.Regions;
using System.Windows;
using System.Windows.Controls;
namespace BlankApp3
{
public partial class App
{
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry) { }
protected override void ConfigureRegionAdapterMappings(RegionAdapterMappings regionAdapterMappings)
{
base.ConfigureRegionAdapterMappings(regionAdapterMappings);
regionAdapterMappings.RegisterMapping(typeof(StackPanel),Container.Resolve<StackAdapter>());
}
// 在此处重写该方法,实现view与viewmodel的连接
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
// type / type
//ViewModelLocationProvider.Register(typeof(UserControl1).ToString(), typeof(UserControl1ViewModel));
// type / factory
//ViewModelLocationProvider.Register(typeof(UserControl1).ToString(), () => Container.Resolve());
// generic factory
//ViewModelLocationProvider.Register(() => Container.Resolve());
// generic type
ViewModelLocationProvider.Register<UserControl1, UserControl1ViewModel>();
}
}
}
Prism DelegateCommand 类封装了两个委托,每个委托都引用了在 ViewModel 类中实现的方法。 它通过调用这些委托来实现 ICommand 接口的 Execute 和 CanExecute 方法。
(1)实例化一个DelegateCommand。
public class ArticleViewModel
{
public DelegateCommand SubmitCommand { get; private set; }
public ArticleViewModel()
{
SubmitCommand = new DelegateCommand<object>(Submit, CanSubmit);
}
void Submit(object parameter)
{
//implement logic
}
bool CanSubmit(object parameter)
{
return true;
}
}
(2)在XAML中Command绑定DelegateCommand。
<Button Command="{Binding SubmitCommand}" CommandParameter="OrderId"/>
复合命令是由多个Module下定义的命令的一个集合体。当执行ShellView中的复合命令时,等同是执行所有视图中注册到复合命令中的全部命令。且只有当所有子命令能够被执行时,复合命令才能够正常执行。
Note: 通常希望一个CompositeCommands 在应用中能够被全局访问,且在将子命令注册到CompositeCommands 时,必须保证CompositeCommands 是唯一的实例,所以需要将CompositeCommands 定义为单例。Prism提供了两种方法实现:
public interface IApplicationCommands
{
CompositeCommand SaveCommand { get; }
}
public class ApplicationCommands : IApplicationCommands
{
private CompositeCommand _saveCommand = new CompositeCommand();
public CompositeCommand SaveCommand
{
get { return _saveCommand; }
}
}
public partial class App : PrismApplication
{
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IApplicationCommands, ApplicationCommands>();
}
}
public DelegateCommand UpdateCommand { get; private set; }
public TabViewModel(IApplicationCommands applicationCommands)
{
UpdateCommand = new DelegateCommand(Update);
applicationCommands.SaveCommand.RegisterCommand(UpdateCommand);
}
public static class ApplicationCommands
{
public static CompositeCommand SaveCommand = new CompositeCommand();
}
public DelegateCommand UpdateCommand { get; private set; }
public TabViewModel()
{
UpdateCommand = new DelegateCommand(Update);
ApplicationCommands.SaveCommand.RegisterCommand(UpdateCommand);
}
这里只介绍使用依赖注入定义的复合命令与控件的绑定
public class MainWindowViewModel : BindableBase
{
private IApplicationCommands _applicationCommands;
public IApplicationCommands ApplicationCommands
{
get { return _applicationCommands; }
set { SetProperty(ref _applicationCommands, value); }
}
public MainWindowViewModel(IApplicationCommands applicationCommands)
{
ApplicationCommands = applicationCommands;
}
}
<Button Content="Save" Command="{Binding ApplicationCommands.SaveCommand}"/>
Note: 当我们不需要已经被注册的子命令时,必须使用该方法移除被注册的子命令,否则可能会导致内存泄漏。
public void Destroy()
{
_applicationCommands.UnregisterCommand(UpdateCommand);
}
Prism提供了一个IActiveAware接口,这个接口定义了一个IsActive属性,当视图被激活时该属性返回TRUE。并提供了一个IsActivateChanged事件,当激活状态被改变时,该事件都会被触发。
public class ApplicationCommands : IApplicationCommands
{
private CompositeCommand _saveCommand = new CompositeCommand(true);
public CompositeCommand SaveCommand
{
get { return _saveCommand; }
}
}
当这个monitorCommandActivity参数是true时,复合命令将会执行一下行为:
- CanExecute: 只有被激活视图才会被判断命令是否可以被执行,非激活视图不被考虑。
- Execute: 只是那些被激活的视图才会执行该方法。
事件聚合是用于实现事件的发布与订阅机制
事件集合器允许多个订阅者订阅同一个发布者事件。负责定位或构建事件,并负责在系统中保存事件的集合。
PubSubEvent是Prism框架下唯一负责连接发布和订阅者的类。主要用于实现各个视图之间的数据传输。
// 创建事件
public class SavedEvent : PubSubEvent<string> { }
// 发布事件
IEventAggregator.GetEvent<SavedEvent>().Publish("some value");
// 订阅事件
IEventAggregator.GetEvent<SavedEvent>().Subscribe(.Subscribe(message=>
{
//do something
});
具体案例代码:
(1)创建事件代码
using Prism.Events;
namespace UsingEventAggregator.Core
{
public class MessageSentEvent : PubSubEvent<string>
{
}
}
(2)发布消息
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using UsingEventAggregator.Core;
namespace ModuleA.ViewModels
{
public class MessageViewModel : BindableBase
{
IEventAggregator _ea;
private string _message = "Message to Send";
public string Message
{
get { return _message; }
set { SetProperty(ref _message, value); }
}
public DelegateCommand SendMessageCommand { get; private set; }
public MessageViewModel(IEventAggregator ea)
{
_ea = ea;
SendMessageCommand = new DelegateCommand(SendMessage);
}
private void SendMessage()
{
_ea.GetEvent<MessageSentEvent>().Publish(Message);
}
}
}
(3)订阅消息并执行一些动作
using Prism.Events;
using Prism.Mvvm;
using System.Collections.ObjectModel;
using UsingEventAggregator.Core;
namespace ModuleB.ViewModels
{
public class MessageListViewModel : BindableBase
{
IEventAggregator _ea;
private ObservableCollection<string> _messages;
public ObservableCollection<string> Messages
{
get { return _messages; }
set { SetProperty(ref _messages, value); }
}
public MessageListViewModel(IEventAggregator ea)
{
_ea = ea;
Messages = new ObservableCollection<string>();
_ea.GetEvent<MessageSentEvent>().Subscribe(MessageReceived);
}
private void MessageReceived(string message)
{
// 这里接收到参数后,可以作为一个函数的启动参数。自定义一些方法
Messages.Add(message);
}
}
}
Note: PubSubEvent类中对Subscribe函数进行了6次重载定义。其中所有的参数如下所示:
**Action action:**发布事件时执行的委托。
ThreadOption threadOption: 指定在哪个线程上接收委托回调。
PublisherThread = 0:与发布者在同一线程
UIThread = 1:UI线程
BackgroundThread = 2:调用在后台线程上异步完成。
bool keepSubscriberReferenceAlive: 当为 true 时,Prism.Events.PubSubEvent`1 保留对订阅者的引用,因此它不会被垃圾收集。如果为True就必须定义取消订阅。
Predicate filter: 事件过滤器。 (重点: public delegate bool Predicate(T obj);)
public MessageListViewModel(IEventAggregator ea)
{
_ea = ea;
Messages = new ObservableCollection<string>();
_ea.GetEvent<MessageSentEvent>().Subscribe(MessageReceived,ThreadOption.PublisherThread, false, (filter) => filter.Contains("Brian"));
// bool string.Contains("Brian"),判断字符串是否包含"Brian"字符串。
当你想取消强引用定义的接收事件时,你可以有两种方式,一是通过委托(订阅事件本身)的方式取消定义。或是获取订阅者token取消订阅。
(1)委托方式取消订阅
public class MainPageViewModel
{
TickerSymbolSelectedEvent _event;
public MainPageViewModel(IEventAggregator ea)
{
_event = ea.GetEvent<TickerSymbolSelectedEvent>();
_event.Subscribe(ShowNews);
}
void Unsubscribe()
{
_event.Unsubscribe(ShowNews);
}
void ShowNews(string companySymbol)
{
//implement logic
}
}
(2)获取订阅者token取消订阅
public class MainPageViewModel
{
TickerSymbolSelectedEvent _event;
SubscriptionToken _token;
public MainPageViewModel(IEventAggregator ea)
{
_event = ea.GetEvent<TickerSymbolSelectedEvent>();
_token = _event.Subscribe(ShowNews);
}
void Unsubscribe()
{
_event.Unsubscribe(_token);
}
void ShowNews(string companySymbol)
{
//implement logic
}
}
定义: 导航被定义为由于用户与应用程序的交互或内部应用程序状态更改,应用程序协调其 UI 更改的过程。
基本导航的案例实现:
using ModuleA.ViewModels;
using ModuleA.Views;
using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;
namespace ModuleA
{
public class ModuleAModule : IModule
{
public void OnInitialized(IContainerProvider containerProvider)
{
var regionManager = containerProvider.Resolve<IRegionManager>();
regionManager.RequestNavigate("RegionName", "ViewName");
// regionManager.RegisterViewWithRegion("LeftRegion", typeof(MessageView)); view discovery实现视图注入相当于一种受限的视图导航方法
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
//添加别名 "CustomName"
// containerRegistry.RegisterForNavigation("CustomName");
//默认名称 "ViewB"
// containerRegistry.RegisterForNavigation();
//指定ViewModel
containerRegistry.RegisterForNavigation<MessageView, MessageViewModel>();
//指定ViewModel并且添加别名
// containerRegistry.RegisterForNavigation("CustomName");
}
}
}
IContainerRegistryExtensions 接口的RegisterForNavigation函数(注册一个导航对象) 实现了三种重载方法。 在上面的示例代码中有展示。
IRegionManager 接口的 RequestNavigate 函数(将视图导航至指定的区域中)实现了8种的功能重载。全部参数介绍说明如下:
string regionName: 区域名称
string target/Uri target/Uri source: 表示导航的视图内容
Action navigationCallback: 导航完成后将执行的导航回调。
NavigationParameters navigationParameters: NavigationParameters 的一个实例,其中包含对象参数的集合。
(1) 给RequestNavigate 添加一个导航完成后的回调函数:
using System;
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
namespace BasicRegionNavigation.ViewModels
{
public class MainWindowViewModel : BindableBase
{
private readonly IRegionManager _regionManager;
private string _title = "Prism Unity Application";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
public DelegateCommand<string> NavigateCommand { get; private set; }
public MainWindowViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
NavigateCommand = new DelegateCommand<string>(Navigate);
}
private void Navigate(string navigatePath)
{
if (navigatePath != null)
_regionManager.RequestNavigate("ContentRegion", navigatePath, NavigationComplete);
}
private void NavigationComplete(NavigationResult result)
{
System.Windows.MessageBox.Show(String.Format("Navigation to {0} complete. ", result.Context.Uri));
}
}
}
(2) 给RequestNavigate 添加NavigationParameters 类型的参数,使得实现viewA导航至viewB时,可以将参数从viewA导航页传递至viewB导航页:
在实现参数传递之前,需要先了解一下:INavigationAware接口类 ,该接口用于用于监视导航的活动,并定义了如下三个方法。
(1) 参数传递代码
namespace ModuleA.ViewModels
{
public class PersonListViewModel : BindableBase
{
readonly IRegionManager _regionManager;
public DelegateCommand<Person> PersonSelectedCommand { get; private set; }
public PersonListViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
PersonSelectedCommand = new DelegateCommand<Person>(PersonSelected);
CreatePeople();
}
private void PersonSelected(Person person)
{
if (person == null)
return;
var parameters = new NavigationParameters();
parameters.Add("person", person);
// 实现参数的传递
_regionManager.RequestNavigate("PersonDetailsRegion", "PersonDetail", parameters);
}
(2) 在实现INavigationAware接口类中的OnNavigatedTo函数实现参数的接收
namespace ModuleA.ViewModels
{
public class PersonDetailViewModel : BindableBase, INavigationAware
{
private Person _selectedPerson;
public Person SelectedPerson
{
get { return _selectedPerson; }
set { SetProperty(ref _selectedPerson, value); }
}
public PersonDetailViewModel()
{
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
if (navigationContext.Parameters.ContainsKey("person"))
{
//Can use either one of these calls to get the person parameter
SelectedPerson = navigationContext.Parameters.GetValue<Person>("person");
//SelectedPerson = navigationContext.Parameters["person"] as Person;
}
}
// 下面函数判定导航条件是否满足
public bool IsNavigationTarget(NavigationContext navigationContext)
{
var person = navigationContext.Parameters.GetValue<Person>("person");
if (SelectedPerson.LastName == person.LastName)
return true;
else
return false;
}
// 页面被切换时触发该函数
public void OnNavigatedFrom(NavigationContext navigationContext)
{
}
}
}
(1)ConfirmNavigationRequest允许用户针对导航请求进行拦截。该方法在OnNavigatedFrom之前执行(注:ConfirmNavigationRequest继承自INavigationAware接口类)
namespace Prism.Regions
{
// Provides a way for objects involved in navigation to determine if a navigation request should continue.
public interface IConfirmNavigationRequest : INavigationAware
{
// Determines whether this instance accepts being navigated away from.
// 参数:
// navigationContext:The navigation context.
// continuationCallback:The callback to indicate when navigation can proceed.
// 此方法的实现者不需要在此方法完成之前调用回调,但他们必须确保最终调用回调。
void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback);
}
}
(2)具体实现案例:
namespace ModuleA.ViewModels
{
public class ViewAViewModel : BindableBase, IConfirmNavigationRequest
{
private string _text = "ViewA";
public string Text
{
get { return _text; }
set { SetProperty(ref _text, value); }
}
public ViewAViewModel()
{
}
public void ConfirmNavigationRequest(NavigationContext navigationContext, Action continuationCallback)
{
bool result = true;
//Demo code only, use DialogService instead of MessageBox in a ViewModel in production code
if (MessageBox.Show("Do you want to navigation?", "Navigate?", MessageBoxButton.YesNo) == MessageBoxResult.No)
{
result = false;
}
continuationCallback(result);
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
}
public bool IsNavigationTarget(NavigationContext navigationContext)
{
return true;
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
}
}
}
具体代码:
namespace ModuleA.ViewModels
{
public class PersonDetailViewModel : BindableBase, INavigationAware
{
private Person _selectedPerson;
IRegionNavigationJournal _journal;
public Person SelectedPerson
{
get { return _selectedPerson; }
set { SetProperty(ref _selectedPerson, value); }
}
public DelegateCommand GoforwardCommand { get; set; }
public DelegateCommand GoBackCommand { get; set; }
public PersonDetailViewModel()
{
GoBackCommand = new DelegateCommand(GoBack);
GoforwardCommand = new DelegateCommand(GoForward);
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
_journal = navigationContext.NavigationService.Journal;
var person = navigationContext.Parameters["person"] as Person;
if (person != null)
SelectedPerson = person;
}
public bool IsNavigationTarget(NavigationContext navigationContext)
{
var person = navigationContext.Parameters["person"] as Person;
if (person != null)
return SelectedPerson != null && SelectedPerson.LastName == person.LastName;
else
return true;
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
}
private void GoBack()
{
_journal.GoBack();
}
private void GoForward()
{
_journal.GoForward();
}
}
}
public class EmployeeDetailsViewModel : INavigationAware
{
...
private IRegionNavigationService navigationService;
public void OnNavigatedTo(NavigationContext navigationContext)
{
navigationService = navigationContext.NavigationService;
}
public DelegateCommand<object> GoBackCommand { get; private set; }
private void GoBack(object commandArg)
{
if (navigationService.Journal.CanGoBack)
{
navigationService.Journal.GoBack();
}
}
private bool CanGoBack(object commandArg)
{
return navigationService.Journal.CanGoBack;
}
}
Note: 如果视图采用view discovery和view inject方式将视图注入到区域,那么视图导航日志将无法实现。只有采用视图导航注入视图的方式才能够实现视图日志。
public interface IDialogAware
{
bool CanCloseDialog(); // 决定了这个对话框是否可以被打开
void OnDialogClosed(); // 当确定会被触发,可以在对话框上的内容通过这里传递出去
void OnDialogOpened(IDialogParameters parameters); // 当对话框被创建时则立刻进入该方法,炳辉接受到传递过来的参数
string Title { get; set; } // 表示对话框窗口的标题
event Action<IDialogResult> RequestClose; // 触发这个事件去关闭对话框,这个事件的订阅就是前面说到的当对话框关闭后的回调函数。
}
3. 调用Show/ShowDialog方法创建对话框视图。
public interface IDialogService
{
void Show(string name, IDialogParameters parameters, Action<IDialogResult> callback);
void Show(string name, IDialogParameters parameters, Action<IDialogResult> callback, string windowName);
void ShowDialog(string name, IDialogParameters parameters, Action<IDialogResult> callback);
void ShowDialog(string name, IDialogParameters parameters, Action<IDialogResult> callback, string windowName);
}
4. IDialogResult 该接口主要用于关闭窗口时,回传的一组结果,已经回调的数据, 以供上面3中的callback函数使用。
public class DialogResult : IDialogResult
{
public DialogResult();
public DialogResult(ButtonResult result);
public DialogResult(ButtonResult result, IDialogParameters parameters);
public IDialogParameters Parameters { get; }
public ButtonResult Result { get; }
}
(1)创建ShowDialog命令代码
private IDialogService _dialogService;
private void ShowDialog()
{
var p = new DialogParameters();
p.Add("message", "Hello from ViewAViewModel"); // 添加传递到对话框的参数
_dialogService.ShowDialog("MessageDialog", p, r =>
// 用于处理对话框关闭传回参数的回调函数(Result, Parameter)
{
if (r.Result == ButtonResult.OK)
{
MessageReceived = r.Parameters.GetValue<string>("myParam");
}
else
{
MessageReceived = "Not closed by user";
}
});
}
(2) 在对话框的上下文代码中的OnDialogOpened函数中接收ShowDialog传递的参数。
public virtual void OnDialogOpened(IDialogParameters parameters)
{
Message = parameters.GetValue<string>("message");
}
(3) 在对话框上下文代码中使用IDialogAware的RequestClose事件向ShowDialog传递参数
protected virtual void CloseDialog(string parameter)
{
ButtonResult result = ButtonResult.None;
if (parameter?.ToLower() == "true")
result = ButtonResult.OK;
else if (parameter?.ToLower() == "false")
result = ButtonResult.Cancel;
var outParameter = new DialogParameters();
outParameter.Add("myParam", "The Dialog was closed by user.");
// 调用RequestClose事件并将参数传递,最后将CloseDialog与DelegateCommand绑定。
RaiseRequestClose(new DialogResult(result, outParameter));
}
public virtual void RaiseRequestClose(IDialogResult dialogResult)
{
RequestClose?.Invoke(dialogResult);
}
using Prism.Ioc;
using Prism.Modularity;
using PrismDemo.Dialogs.Dialogs;
namespace PrismDemo.Dialogs
{
public class DialogsModule : IModule
{
public void OnInitialized(IContainerProvider containerProvider)
{
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterDialog<MessageDialog, MessageDialogViewModel>();
}
}
}
Prism官网: https://prismlibrary.com/docs/wpf/region-navigation/navigation-journal.html
痕迹g: https://www.cnblogs.com/zh7791/category/1893907.html
github:搜索Prism-WPF-Samples-master / Prism-Samples-Wpf-master