【WPF】Prism P2
一、弹窗设置
Step1 在模块A创建弹窗A和弹窗B,注意,还是要使用【用户控件】
<UserControl x:Class="ModuleA.Views.DialogA" 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:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:ModuleA.Views" mc:Ignorable="d" Height="450" Width="800"> <Grid Background="White"> <Grid.RowDefinitions> <RowDefinition Height="auto" /> <RowDefinition /> <RowDefinition Height="auto" /> </Grid.RowDefinitions> <TextBlock Text="温馨提示" /> <TextBlock VerticalAlignment="Center" Text="这是DialogA" FontSize="30" Grid.Row="1" /> <StackPanel Orientation="Horizontal" Grid.Row="2"> <Button Content="取消" Margin="5" FontSize="15" Command="{ Binding CancelCommand }" /> <Button Content="确定" Margin="5" FontSize="15" Command="{ Binding ConfirmCommand }" /> </StackPanel> </Grid> </UserControl>
目录位置:
Step2 创建弹窗A和B对应的视图类,并且该类需要实现IDialogAware接口(仅实例A)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using ImTools; using Prism.Commands; using Prism.Services.Dialogs; namespace ModuleA.ViewModels { /* 弹窗视图类需要实现 Prism.Services.Dialogs.IDialogAware接口 */ internal class DialogAViewModel : IDialogAware { public string Title { get; set; } public event Action<IDialogResult> RequestClose; /* 设定弹窗的确认和取消命令 */ public DelegateCommand CancelCommand { get; set; } public DelegateCommand ConfirmCommand { get; set; } public DialogAViewModel() { /* 命令初始化 */ CancelCommand = new DelegateCommand(cancel); ConfirmCommand = new DelegateCommand(confirm); } /* 设置这个弹窗允许关闭 */ public bool CanCloseDialog() { return true; } /* 当弹窗关闭时回调方法 */ public void OnDialogClosed() { DialogParameters keyValuePairs = new DialogParameters(); keyValuePairs.Add("Value", "Message From DialogA"); RequestClose?.Invoke(new DialogResult(ButtonResult.OK, keyValuePairs)); } /* 当弹窗打开时回调方法,接受一个参数对象 */ public void OnDialogOpened(IDialogParameters parameters) { if (parameters.ContainsKey("Title")) { Title = parameters.GetValue<string>("Title"); } } /* 确认方法 */ private void confirm() { OnDialogClosed(); } /* 取消方法 */ private void cancel() { RequestClose?.Invoke(new DialogResult(ButtonResult.No)); } } }
回到模块AProfile类注册弹窗A和B:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using ModuleA.ViewModels; using ModuleA.Views; using Prism.Ioc; using Prism.Modularity; namespace ModuleA { public class ModuleAProfile : IModule { public void OnInitialized(IContainerProvider containerProvider) { } public void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterForNavigation<ViewD, ViewDViewModel>(); containerRegistry.RegisterDialog<DialogA, DialogAViewModel>(); containerRegistry.RegisterDialog<DialogB, DialogBViewModel>(); } } }
MainViewModel类追加弹窗打开方法:
当回调触发时可以接受弹窗信息发送的参数
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Prism.Commands; using Prism.Mvvm; using Prism.Regions; using Prism.Services.Dialogs; namespace WPF_Prism.ViewModels { internal class MainViewModel : BindableBase { public DelegateCommand<string> OpenCommand { private set; get; } public DelegateCommand BackCommand { private set; get; } public DelegateCommand<string> OpenDialogCommand { private set; get; } private readonly IRegionManager regionManager; private readonly IDialogService dialogService; private IRegionNavigationJournal journal; /* 初始化时通过构造器注入区域管理器对象 */ public MainViewModel(IRegionManager regionManager, IDialogService dialogService) { /* 命令逻辑初始化 */ OpenCommand = new DelegateCommand<string>(Open); BackCommand = new DelegateCommand(Back); OpenDialogCommand = new DelegateCommand<string> (OpenDialog); /* 初始化Prism资源 */ this.regionManager = regionManager; this.dialogService = dialogService; } private void Open(string obj) { /* 可以向路由传递参数 */ NavigationParameters keys = new NavigationParameters(); keys.Add("Title", "nav-para"); /* 通过区域管理器对象,指定区域名获取该区域对象,并导航到目标视图控件对象上 */ regionManager.Regions["ContentRegion"].RequestNavigate(obj, navigationCallback => { if (journal == null && (bool)navigationCallback.Result) journal = navigationCallback.Context.NavigationService.Journal; }, keys); } private void Back() { if (journal != null && journal.CanGoBack) { journal.GoBack(); } } /* 弹窗打开方法 */ private void OpenDialog(string obj) { /* 调用弹窗展示方法之前可以传递参数信息 */ DialogParameters keyValuePairs = new DialogParameters(); keyValuePairs.Add("Title", obj); /* 在该弹窗关闭之后可以回调处理逻辑 */ dialogService.ShowDialog(obj, keyValuePairs, callback => { /* 当为确认时再处理逻辑 */ if (callback.Result == ButtonResult.OK) { string result = callback.Parameters.GetValue<string>("Value"); Console.WriteLine(result); } }); } } }
主窗口xaml追加弹窗按钮支持:
<Window x:Class="WPF_Prism.Views.MainView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WPF_Prism" xmlns:prism="http://prismlibrary.com/" prism:ViewModelLocator.AutoWireViewModel="True" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="auto" /> <RowDefinition Height="auto" /> <RowDefinition /> </Grid.RowDefinitions> <StackPanel Orientation="Horizontal"> <Button Margin="5" Command="{ Binding OpenCommand }" CommandParameter="ViewA">ViewA</Button> <Button Margin="5" Command="{ Binding OpenCommand }" CommandParameter="ViewB">ViewB</Button> <Button Margin="5" Command="{ Binding OpenCommand }" CommandParameter="ViewC">ViewC</Button> <Button Margin="5" Command="{ Binding OpenCommand }" CommandParameter="ViewD">ViewD</Button> <Button Margin="5" Command="{ Binding OpenCommand }" CommandParameter="ViewE">ViewE</Button> <Button Margin="5" Command="{ Binding BackCommand }">上一页</Button> </StackPanel> <StackPanel Grid.Row="1" Orientation="Horizontal"> <Button Margin="5" Command="{ Binding OpenDialogCommand }" CommandParameter="DialogA">DialogA</Button> <Button Margin="5" Command="{ Binding OpenDialogCommand }" CommandParameter="DialogB">DialogB</Button> </StackPanel> <ContentControl Grid.Row="2" prism:RegionManager.RegionName="ContentRegion" /> </Grid> </Window>
执行预览:
关闭时参数接收的Debug调试
二、事件订阅与发布
在模块A中新建event目录,并添加MessageEvent类:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using DryIoc.Messages; using Prism.Events; namespace ModuleA.Event { /* 定义一般string的消息事件类 */ public class MessageEvent : PubSubEvent<string> { } /* 定义业务数据实体的消息事件类 */ public class BusEvent : PubSubEvent<BusData> { } public class BusData { private int _id; private string _code; private string _message; public int Id { get { return _id; } set { _id = Id; } } public string Code { get { return _code; } set { _code = Code; } } public string Message { get { return _message; } set { _message = Message; } } } }
在弹窗A的类的构造器参数中追加事件聚合器接口:
聚合器根据泛型获取对应的事件对象,并调用订阅回调方法
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using ModuleA.Event; using Prism.Events; namespace ModuleA.Views { /// <summary> /// DialogA.xaml 的交互逻辑 /// </summary> public partial class DialogA : UserControl { public DialogA(IEventAggregator eventAggregator) { InitializeComponent(); eventAggregator.GetEvent<MessageEvent>().Subscribe(arg => { MessageBox.Show($"接收到消息:{arg}"); }); } } }
弹窗A的视图类,在初始化时发布消息:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using ImTools; using ModuleA.Event; using Prism.Commands; using Prism.Events; using Prism.Services.Dialogs; namespace ModuleA.ViewModels { /* 弹窗视图类需要实现 Prism.Services.Dialogs.IDialogAware接口 */ internal class DialogAViewModel : IDialogAware { public string Title { get; set; } public event Action<IDialogResult> RequestClose; /* 设定弹窗的确认和取消命令 */ public DelegateCommand CancelCommand { get; set; } public DelegateCommand ConfirmCommand { get; set; } public DialogAViewModel(IEventAggregator eventAggregator) { /* 命令初始化 */ CancelCommand = new DelegateCommand(cancel); ConfirmCommand = new DelegateCommand(confirm); eventAggregator.GetEvent<MessageEvent>().Publish("Hello"); } /* 设置这个弹窗允许关闭 */ public bool CanCloseDialog() { return true; } /* 当弹窗关闭时回调方法 */ public void OnDialogClosed() { DialogParameters keyValuePairs = new DialogParameters(); keyValuePairs.Add("Value", "Message From DialogA"); RequestClose?.Invoke(new DialogResult(ButtonResult.OK, keyValuePairs)); } /* 当弹窗打开时回调方法,接受一个参数对象 */ public void OnDialogOpened(IDialogParameters parameters) { if (parameters.ContainsKey("Title")) { Title = parameters.GetValue<string>("Title"); } } /* 确认方法 */ private void confirm() { OnDialogClosed(); } /* 取消方法 */ private void cancel() { RequestClose?.Invoke(new DialogResult(ButtonResult.No)); } } }
执行效果:
先触发消息订阅回调,之后再打开弹窗
三、MaterialDesign UI库
地址:https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit
发现直接打开项目无法运行:
错误代码是:NETSDK1141
定位到项目的global.json文件
打开发现要求dotnet版本是8.0.100
但是我在vs的设置里面查看了已经安装的dotnet环境库
可以发现已经安装了8.0的环境
然后查看本地DotNet环境时发现使用的版本是9.0.100
命令: dotnet --info
所以猜想是因为global.json的版本和本地环境不一致导致,将global.json改为9.0.100版本
保存后项目启动正常...
可以打包发布出来,里面有组件的演示案例:
四、MD UI库引入到项目
1、NUGET包管理找到 MD主题资源并下载:
搜素关键字:MaterialDesignThemes
2、在App.xaml中,追加关于MD的资源引用
注意这里不要使用MD官方的,需要改用视频地址里的资源引用方式
<prism:PrismApplication x:Class="NoteApp.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:NoteApp" xmlns:prism="http://prismlibrary.com/" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <materialDesign:BundledTheme BaseTheme="Dark" PrimaryColor="DeepPurple" SecondaryColor="Lime" /> <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </prism:PrismApplication>
3、在主窗口编写一个按钮,测试样式是否有效
<Window x:Class="NoteApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:NoteApp" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="auto" /> <RowDefinition /> </Grid.RowDefinitions> <Button Content="hello" Height="50" /> </Grid> </Window>
启动后预览展示: