什麼是Prism: 1.WPF Prism是一個用於構建模塊化、可擴展和可重用的WPF應用程式的框架。它基於MVVM模式,提供了一種簡單且靈活的方式來管理複雜的WPF應用程式。 2.Prism框架提供了一些核心概念,包括模塊化開發、依賴註入、命令模式、導航和事件聚合等。它還提供了一些實用工具和類來簡 ...
什麼是Prism:
1.WPF Prism是一個用於構建模塊化、可擴展和可重用的WPF應用程式的框架。它基於MVVM模式,提供了一種簡單且靈活的方式來管理複雜的WPF應用程式。
2.Prism框架提供了一些核心概念,包括模塊化開發、依賴註入、命令模式、導航和事件聚合等。它還提供了一些實用工具和類來簡化開發過程,例如模塊載入器、事件聚合器、導航器等。
3.Prism框架的主要目標是幫助開發人員構建易於維護和擴展的WPF應用程式,同時提高代碼的可重用性和可測試性。
Github:https://github.com/PrismLibrary/Prism
Prism包括哪些功能模塊:
1.Region(區域管理)
2.Module(模塊)
3.View Injection(視圖註入)
4.ViewModelLocationProvider(視圖模型定位)
5.Command(綁定相關)
6.Event Aggregator (事件聚合器)
7.Navigation(導航)
8.Dialog(對話框)
功能↓ / →框架名 | Prism | Mvvmlight | Micorosoft.Toolkit.Mvvm |
通知 | BindableBase | ViewModelBase | ObservableObject |
命令 | DelegateCommand | RelayCommand | Async/RelayCommand |
聚合器 | IEventAggregator | IMessenger | IMessenger |
模塊化 | √ | × | × |
容器 | √ | × | × |
依賴註入 | √ | × | × |
導航 | √ | × | × |
對話 | √ | × | × |
創建Prism應用程式:
第一步:創建WPF應用程式(我這裡用NET6.0)
第二步:引用Prism.Unity框架
第三部:修改App.xaml文件
<prism:PrismApplication x:Class="WpfApp_test.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Shell" xmlns:prism="http://prismlibrary.com/"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </prism:PrismApplication>
public partial class App : PrismApplication { protected override void RegisterTypes(IContainerRegistry containerRegistry) { } protected override Window CreateShell() { return Container.Resolve<MainWindow>(); } }
View和ViewModel實現綁定
添加Views和ViewModels文件夾,在Views文件夾里添加MainWindow.xaml和在ViewModels添加MainWindowViewModel.cs
<Window x:Class="WpfApp_test.Views.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:WpfApp_test.Views" xmlns:prism="http://prismlibrary.com/" prism:ViewModelLocator.AutoWireViewModel="True" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> </Grid> </Window>
或者在App.cs中進行註冊
protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterForNavigation<MainWindow, MainWindowViewModel>(); }
亦或者在MainWindow.xaml.cs
this.DataContext = new MainWindowViewModel();
View和ViewModel數據綁定
<Window x:Class="WpfApp1.Views.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:WpfApp1.Views" xmlns:prism="http://prismlibrary.com/" xmlns:i="http://schemas.microsoft.com/xaml/behaviors" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"> <TextBlock Text="{Binding Title}" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="20"/> <Button Content="確定" Command="{Binding TitleCommand}" Height="30" Width="50"/> <Button FontSize="30" Content="帶參數" Margin="10" Height="60" Command="{Binding GetParameterCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self}}"/> <Button x:Name="button" FontSize="30" Content="behaviors帶參數" Margin="10" Height="60" > <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <i:InvokeCommandAction Command="{Binding BehaviorsClickCommand}" CommandParameter="{Binding ElementName=button}"/> </i:EventTrigger> </i:Interaction.Triggers> </Button> </StackPanel> </Grid> </Window>
public class MainWindowViewModel: BindableBase { private string _title; public string Title { get { return _title; } set { _title = value; RaisePropertyChanged(); } } public DelegateCommand TitleCommand { get; private set; } public DelegateCommand<Button> GetParameterCommand { get; private set; } public DelegateCommand<Button> BehaviorsClickCommand { get; private set; } public MainWindowViewModel() { TitleCommand = new DelegateCommand(TitleAction); GetParameterCommand = new DelegateCommand<Button>(GetParameterAction); BehaviorsClickCommand = new DelegateCommand<Button>(BehaviorsClickAction); } private void TitleAction() { Title = "Prism應用程式!"; } private void GetParameterAction(Button obj) { obj.Content = "GetParameter"; } private void BehaviorsClickAction(Button obj) { obj.Content = "BehaviorsClick"; } }
區域(Region)
頁面顯示的區域劃分稱N個Region, 此時, 每個Region將變成了動態分配區域。它將負責承擔我們的UI組件或者控制項。
區域定義
添加一個用戶控制項頁面Content.xaml
在MainWindow頁面添加
<ContentControl x:Name="Content" />
<Grid Grid.Row="1"> <!--<ContentControl prism:RegionManager.RegionName="{x:Static share:RegionNames.MainRegion}"/>--> <ContentControl x:Name="Content" /> </Grid>
在MainWindow.xaml.cs
public partial class MainWindow : Window { public MainWindow(IRegionManager regionManager) { InitializeComponent(); //為界面元素註冊區域 RegionManager.SetRegionName(Content, "ContentRegion"); //為指定區域指定頁面 regionManager.RegisterViewWithRegion("ContentRegion", typeof(Content)); } }
在Prism中, 控制項都支持註冊Region, 只是有些控制項需要自己實現一個RegionAdapters(區域適配器),Prism提供了許多內置得RegionAdapter。
如:ContentControlRegionAdapter ,ItemsControlRegionAdapter ,SelectorRegionAdapter等。
模塊(Module)
對於微服務的思想來說,對於特定功能服務都可以獨立存在,在WPF中那麼意味著, 每個獨立的功能我們都可以稱之為模塊。
模塊添加操作流程:
1.添加一個新的項目,WPF用戶控制項項目。
2.添加引用,Prism.Unity框架。
3.添加一個類。並繼承於IModule,實現OnInitialized和RegisterTypes方法
4.添加兩個文件夾Views和ViewModels
5.項目-->屬性-->生成-->事件--生成後事件
xcopy "$(ProjectDir)\bin\Debug\net6.0-windows\$(ProjectName).dll" "$(SolutionDir)\WPFClient\bin\Debug\net6.0-windows\Modules\" /Y /S xcopy "$(ProjectDir)\bin\Release\net6.0-windows\$(ProjectName).dll" "$(SolutionDir)\WPFClient\bin\Release\net6.0-windows\Modules\" /Y /S
這個是生成該項目後,dll之間複製到主項目的bin目錄下去。
6.在主項目WPFClient的bin目錄下添加一個文件夾Modules。
7.在主項目的APP類文件里重寫CreateModuleCatalog方法
protected override IModuleCatalog CreateModuleCatalog() { return new DirectoryModuleCatalog() { ModulePath = AppContext.BaseDirectory + $"\\Modules" //獲取WPFModule.dll的目錄 }; }
還有一種是通過引用項目的方法來添加
/// <summary> /// 通過引用來獲取其它模塊的頁面 /// </summary> /// <param name="moduleCatalog"></param> protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) { base.ConfigureModuleCatalog(moduleCatalog); moduleCatalog.AddModule<WPF.Common.CommonProfile>();//模塊的IModule類 }
8.生成解決方法。
IRegionManager
怎樣把子模塊的頁面呈現到主項目的ContentControl 區域中呢?
案列:
public class ImageModuleProfile : IModule { private readonly IRegionManager _regionManager; public ImageModuleProfile(IRegionManager regionManager) { _regionManager = regionManager; } public void OnInitialized(IContainerProvider containerProvider) {
//ImageView是子項目的頁面, ContentControlName.MainmoduleImagemoduleReginName是區域的名稱 _regionManager.RegisterViewWithRegion<ImageView>(ContentControlName.MainmoduleImagemoduleReginName); } public void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterForNavigation<ImageView, ImageViewModel>(); } }
或者
_regionManager.RegisterViewWithRegion(ContentControlName.MainmoduleImagemoduleReginName, typeof(ImageView));
聚合器IEventAggregator
//創建事件 public class SavedEvent : PubSubEvent<string> { } //發佈 IEventAggregator.GetEvent<SavedEvent>().Publish("some value"); //訂閱 IEventAggregator.GetEvent<SavedEvent>().Subscribe(.Subscribe(message=> { //do something });
Navigation導航功能
案例:
IRegionManager regionManager = …;//構造函數中獲取 regionManager.RequestNavigate("RegionName", "ViewName");//跳轉頁面
帶參數的跳轉
var param = new NavigationParameters(); param.Add("Parameter", param); _regionManger.RequestNavigate("RegionName", "ViewName", param); //類似URL地址傳遞參數 _regionManger.RequestNavigate("RegionName", "ViewName?id=1&Name=xiaoming");
INavigationAware
VM類繼承該介面要實現3個方法
public void OnNavigatedTo(NavigationContext navigationContext) { } public bool IsNavigationTarget(NavigationContext navigationContext) { return true; } public void OnNavigatedFrom(NavigationContext navigationContext) { }
OnNavigatedTo: 導航完成前, 此處可以傳遞過來的參數以及是否允許導航等動作的控制。
IsNavigationTarget: 調用以確定此實例是否可以處理導航請求。否則新建實例
OnNavigatedFrom: 當導航離開當前頁時, 類似打開A, 再打開B時, 該方法被觸發。
接受跳轉過來帶的參數
public void OnNavigatedTo(NavigationContext navigationContext) { var id = navigationContext.Parameters.GetValue<int>("id"); var name = navigationContext.Parameters["Name"].ToString(); }
INavigationAware
該介面繼承於INavigationAware, 所以, 它多了一個功能: 允許用戶針對導航請求進行攔截。
//多了一個回調函數, 該值覺得是否攔截該導航請求 void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback);
當打開新的導航時, 或許有些情況下你需要經過用戶進行確認, 這個時候, IConfirmNavigationRequest介面可以滿足需求, 如下:
public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback) { bool result = true; if (MessageBox.Show("確認導航?", "溫馨提示", MessageBoxButton.YesNo) == MessageBoxResult.No) result = false; //通過回調當前返回的確認結果,決定是否啟動該導航 continuationCallback(result); }
Navigation Journal
導航日誌, 其實就是對導航系統的一個管理功能, 理論上來說, 我們應該知道我們上一步導航的位置、以及下一步導航的位置, 包括我們導航的歷史記錄。以便於我們使用導航對應用程式可以靈活的控制。
IRegionNavigationJournal
該介面包含以下功能:
GoBack() : 返回上一頁
CanGoBack : 是否可以返回上一頁
GoForward(): 返回後一頁
CanGoForward : 是否可以返回後一頁
IDialogAware對話框
public interface IDialogAware { string Title { get; } event Action<IDialogResult> RequestClose; bool CanCloseDialog(); void OnDialogClosed(); void OnDialogOpened(IDialogParameters parameters); }
註冊對話框 RegisterDialog
protected override void RegisterTypes(IContainerRegistry containerRegistry) { //僅註冊視圖 containerRegistry.RegisterDialog<MessageDialog>(); //註冊視圖時綁定VM containerRegistry.RegisterDialog<MessageDialog, MessageDialogViewModel>(); //添加別名 containerRegistry.RegisterDialog<MessageDialog>("DialogName"); }
使用IDialogService介面 Show/ShowDialog 方法調用對話框
private readonly IDialogService dialogService; private void ShowDialog() { DialogParameters keys = new DialogParameters(); keys.Add("message", "Hello,Prism!"); dialogService.ShowDialog("MessageDialog", keys, arg => { }); }