1、簡單實現
①、建立使用者控制元件
跨模組的視窗彈出,只需要建立視窗的內容即可,也就是使用者控制元件,這裡是在Views資料夾下,建立DialogContentView使用者控制元件。
需要注意的是,預設情況下,如果需要對彈出視窗進行樣式設定的話,需要透過prism:Dialog.WindowStyle來進行設定。
<UserControl x:Class="Zhaoxi.PrismDialog.Views.DialogContentView" xmlns:prism="http://prismlibrary.com/" ......> <prism:Dialog.WindowStyle> <Style TargetType="Window"> <Setter Property="Width" Value="500"/> <Setter Property="Height" Value="400"/> <!--設定WindowStyle方式的無邊款--> <!--<Setter Property="WindowStyle" Value="None"/> <Setter Property="AllowsTransparency" Value="True"/>--> <!--設定WindowChrome的無邊款--> <Setter Property="WindowChrome.WindowChrome"> <Setter.Value> <WindowChrome GlassFrameThickness="-1"/> </Setter.Value> </Setter> </Style> </prism:Dialog.WindowStyle> </UserControl>
②、建立ViewModel
在ViewModels資料夾中建立DialogContentViewModel類並實現IDialogAware
介面。
public class DialogContentViewModel : IDialogAware { public string Title => "跨域彈出來的子視窗標題"; //關閉彈窗的操作 public event Action<IDialogResult> RequestClose; //是否允許關閉視窗 public bool CanCloseDialog() { //可以根據情況做一下業務判斷 return true; } //視窗關閉或主動觸發RequestClose事件時呼叫 public void OnDialogClosed() { } //視窗開啟時呼叫 public void OnDialogOpened(IDialogParameters parameters) { } }
③、註冊View
在App的RegisterTypes方法中透過呼叫IContainerRegistry物件的RegisterDialog方法進行DialogContentView的註冊
RegisterDialog<TView>(string name = null):註冊對話型別,可以傳入string作為使用時的key。
需要注意的是,如果沒有傳入name引數,使用ShowDialog展示時,則根據註冊的對話型別名稱來查詢。如果傳入了name,則必須根據name來查詢。
public partial class App : PrismApplication { protected override Window CreateShell() { return Container.Resolve<Views.MainWindow>(); } protected override void RegisterTypes(IContainerRegistry containerRegistry) { //註冊一個視窗型別 containerRegistry.RegisterDialog<Views.DialogContentView>(); } }
④、定義彈出視窗命令
透過IOC依賴注入,獲得IDialogService屬性物件。
定義命令,在命令中呼叫IDialogService物件的ShowDialog方法來展示串列埠。
ShowDialog(string name):展示模態對話方塊,如果註冊時,指定了對話名稱,則根據名稱在IOC的對話容器中查詢。否則就根據對話型別的名稱進行查詢。至於對話的父類視窗,預設情況下會自動使用Prism內建的預設視窗物件。
Show(string name):的用法與ShowDialog(string name)用法一樣,只不過展示的是非模態對話方塊。
public class MainWindowViewModel:BindableBase { private string _btnContent = "跨域彈窗"; public string BtnContent { get { return _btnContent; } set { SetProperty(ref _btnContent, value); } } //IOC依賴注入 [Dependency] public IDialogService _dialogService { get; set; } public ICommand BtnCommand { get => new DelegateCommand(() => { //展示視窗 _dialogService.ShowDialog("DialogContentView"); }); } }
⑤、主視窗中繫結命令
<Window ......> <Grid> <StackPanel> <Button Content="{Binding BtnContent}" Command="{Binding BtnCommand}"/> </StackPanel> </Grid> </Window>
2、註冊父類視窗
在上面的實現過程中,我們只建立了使用者控制元件,而使用者控制元件的父類容器,即彈出來的視窗物件則使用了Prism中預設的Dialog視窗。也因此,預設情況下,如果需要對彈出的視窗進行設定,要在使用者控制元件中透過prism:Dialog.WindowStyle來進行預設視窗的樣式設定。
然而透過prism:Dialog.WindowStyle來進行視窗的樣式設定的做法本來就不是很符合xaml的設計規範,而且這隻能對當前的使用者控制元件起效果,如果有多個控制元件希望進行統一的視窗樣式處理的話,在每個使用者控制元件中都編寫一樣的程式碼會顯得很冗餘。較好的解決方案就是重新建立並設定好一個父類窗體,然後註冊到IOC的對話視窗容器中。
成功為對話設定了父類視窗後,父類視窗的樣式就可以跟平常的WPF視窗一樣直接在XAML中進行設定了。其在XAML中設定的樣式的優先順序高於prism:Dialog.WindowStyle。
①、建立父類窗體
在程式集中新建DialogBase資料夾(資料夾名稱並不重要,甚至可以不用建立)並在其中建立DialogWindowBase視窗。
在後臺程式碼實現IDialogWindow,簡化一下Result屬性
<Window ...... WindowStartupLocation="CenterScreen" Background="Transparent" ResizeMode="NoResize" Title="DialogWindowBase" Height="300" Width="500"> <WindowChrome.WindowChrome> <WindowChrome GlassFrameThickness="-1"/> </WindowChrome.WindowChrome> <Grid> </Grid> </Window>
public partial class DialogWindowBase : Window, IDialogWindow { public DialogWindowBase() { InitializeComponent(); } public IDialogResult Result { get; set; } }
②、註冊父類窗體型別
透過RegisterDialogWindow進行對話父類視窗型別的註冊後,會優先使用,而不會自動使用預設的對話視窗型別物件。
RegisterDialogWindow<TWindow>([string name]):註冊對話的父類視窗型別。
當註冊多個父類視窗型別時,可以傳入name方便後面展示時透過key來指定視窗型別,需要注意註冊時一旦指定了name,展示時就必須要指定name,否則找不到對應的父類視窗物件。
需要注意的是,要進行註冊的對話父類視窗的後臺程式碼中都必須實現IDialogWindow介面,否則無法註冊。
public partial class App : PrismApplication { protected override Window CreateShell() { return Container.Resolve<Views.MainWindow>(); } protected override void RegisterTypes(IContainerRegistry containerRegistry) { //註冊一個對話型別 containerRegistry.RegisterDialog<DialogContentView>(); //註冊一個對話父類視窗型別 containerRegistry.RegisterDialogWindow<DialogWindowBase>(); //還可以註冊多個父類視窗型別,然後根據key來指定 } }
③、展示視窗
透過IOC依賴注入,獲得IDialogService
屬性物件。
定義命令,在命令中呼叫IDialogService
物件的ShowDialog
方法來展示串列埠。
-
當註冊的對話父類視窗型別只有一個且沒有指定名稱時,prism會自動去使用,因此只要指定對話型別即可。
public class MainWindowViewModel:BindableBase { ...... [Dependency] public IDialogService _dialogService { get; set; } public ICommand BtnCommand { get => new DelegateCommand(() => { _dialogService.ShowDialog("DialogContentView"); }); } }
3、指定父類窗體
當註冊了多個父類窗體時,可以透過名稱來區分。
①、註冊多個父類視窗
public partial class App : PrismApplication { protected override Window CreateShell() { return Container.Resolve<Views.MainWindow>(); } protected override void RegisterTypes(IContainerRegistry containerRegistry) { //註冊一個對話型別 containerRegistry.RegisterDialog<DialogContentView>("DialogOne"); containerRegistry.RegisterDialog<DialogContentView>("DialogTwo"); //這裡為了方便就不再建立一個新的使用者控制元件了 //註冊一個對話父類視窗型別 containerRegistry.RegisterDialogWindow<DialogWindowBase>("windowBase"); //可以註冊多個父類視窗型別,然後根據key來指定 containerRegistry.RegisterDialogWindow<DialogWindowOne>("windowOne"); } }
②、指定展示
需要注意的是,如果註冊的對話指定了名稱,展示時沒有使用匹配的名稱會導致找不到而報異常;如果註冊的窗體型別都指定了名稱,
展示時沒有指定名稱則會使用prism框架中預設的窗體型別。
public class MainWindowViewModel:BindableBase { ...... [Dependency] public IDialogService _dialogService { get; set; } public ICommand BtnCommand { get => new DelegateCommand(() => { //指定展示的對話及父類窗體 _dialogService.ShowDialog("DialogOne",null,null, "windowBase"); }); } }
4、資料傳遞
當需要向彈出窗體的內容(即我們建立的使用者控制元件)傳遞一些資料的時候,可以透過ShowDialog方法來實現。
①、傳遞資料
ShowDialog(string name, IDialogParameters parameters, Action<IDialogResult> callback, string windowName):展示對話視窗。
parameters:向對話視窗傳遞的資料物件。
DialogParameters:IDialogParameters的子類,用法跟字典是一樣的,可以用DialogParameters物件封裝資料後傳遞給對話視窗。
public class MainWindowViewModel:BindableBase { ...... [Dependency] public IDialogService _dialogService { get; set; } public ICommand BtnCommand { get => new DelegateCommand(() => { //建立資料載體 var dialogParameters = new DialogParameters(); dialogParameters.Add("paramKey", "paramValue"); //展示視窗並進行資料傳遞 _dialogService.ShowDialog("DialogOne", dialogParameters, null, "windowBase"); }); } }
②、資料處理
傳遞的資料物件會在視窗開啟時,傳遞給對應的IDialogAware
子類物件(一般就是彈出視窗的ViewModel)的OnDialogOpened
方法。因此,可以在OnDialogOpened
方法中對資料進行處理。
public class DialogContentViewModel : BindableBase,IDialogAware { ...... public void OnDialogOpened(IDialogParameters parameters) { PassValue = parameters.GetValue<string>("paramKey"); } private string _passValue; public string PassValue { get { return _passValue; } set { SetProperty(ref _passValue, value); } } }
5、回撥函式
當彈出的視窗關閉時需要執行回撥函式,也是透過ShowDialog方法來實現的。
①、設定回撥函式
ShowDialog(string name, IDialogParameters parameters, Action<IDialogResult> callback, string windowName):展示對話視窗。
callback:對話視窗的回撥函式,為一個接收IDialogResult型別引數的Action物件。設定後會自動掛載到對應的IDialogAware子類物件(一般就是彈出視窗的ViewModel)RequestClose事件上,也就是可以透過RequestClose事件來呼叫callback回撥函式。
需要注意的是RequestClose事件的觸發,會先呼叫視窗的關閉函式,再執行回撥函式。對話視窗的正常關閉也會執行回撥函式。
public class MainWindowViewModel:BindableBase { ...... [Dependency] public IDialogService _dialogService { get; set; } public ICommand BtnCommand { get => new DelegateCommand(() => { var dialogParameters = new DialogParameters(); dialogParameters.Add("paramKey", "paramValue"); _dialogService.ShowDialog("DialogOne", dialogParameters, DialogCallBack, "windowBase"); }); } //對話視窗的回撥函式 private void DialogCallBack(IDialogResult result) { //可以根據傳過來的result做業務邏輯處理 } }
②、呼叫回撥函式
在對應的ViewModel上定義命令,觸發RequestClose
事件。
public DelegateCommand CloseCommand { get; set; } public DialogContentViewModel() { CloseCommand = new DelegateCommand(OnClose); } private void OnClose() { IDialogResult dialogResult = new DialogResult(); dialogResult.Parameters.Add("A", true); RequestClose?.Invoke(dialogResult); }
來源:https://blog.csdn.net/jjailsa/article/details/135972127