Prism系列之如何使用弹窗
自定义弹窗窗口
基础弹窗
-
先定义一个窗口类
CustomDialog
,并实现IDialogWindow
接口,xaml
代码部分不需要修改。public partial class CustomDialog : Window, IDialogWindow { public CustomDialog() { InitializeComponent(); } public IDialogResult Result { get; set; } }
-
随后在
App.xaml.cs
中注册protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterDialog<GreetingView>(); containerRegistry.RegisterDialogWindow<CustomDialog>(); }
-
接下来正常使用弹窗服务即可,以下是运行效果,为了确认真的使用了
CustomDialog
, 我在CustomDialog.xaml
中设置了Background = "Red"
。
注册多个自定义弹窗
-
如果我们的项目里不止一个自定义弹窗模板,根据不同的需求使用不同的弹窗,那么我们应该如何做?
-
先再定义一个窗口类
MessageVDialog
,代码与CustomDialog
一致,不同的是将背景改为Green
,并且在App.xaml.cs
中注册protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterDialog<GreetingView>(); containerRegistry.RegisterDialogWindow<CustomDialog>(); containerRegistry.RegisterDialogWindow<MessageVDialog>(); // 最后一个注册的DialogWindow将作为默认弹窗模板 }
-
运行效果:
- 如果在
App.xaml.cs
将注册顺序颠倒一下,先注册MessageVDialog
后注册CustomDialog
,那么将默认使用CustomDialog
那么如何在使用弹窗的时候指定特定的弹窗模板?
-
官方文档 中没有说明
-
问了ChatGPT,给了一堆复杂的配置,说需要自定义实现
DialogService
,没有尝试(大概率是个错误的答案) -
查看源码有没有解决方案,还真找到了答案,在
DialogService.ShowDialog
中发现了一个参数:KnownDialogParameters.WindowName = "windowName"
-
于是我反过来问GPT
WindowName
参数有没有效果,给我的回答是没有用 -
纠错GPT,GPT采纳了建议
-
偏题了,回过头来看下如何传入参数
// App.xaml.cs protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterDialog<GreetingView>(); containerRegistry.RegisterDialogWindow<CustomDialog>("CustomDialog"); containerRegistry.RegisterDialogWindow<MessageVDialog>(); // 最后一个注册的DialogWindow将作为默认弹窗模板 } // MainViewModel.cs DialogParameters para = new DialogParameters() { { KnownDialogParameters.WindowName, "CustomDialog"}, // 如果注释该行,则使用 MessageVDialog 模板 }; DialogService.ShowDialog(nameof(GreetingView), para);
自定义弹窗模板的内容
-
之前注册了
MessageVDialog
,但是显示的弹窗的内容全部是GreetingView
界面,现在想要在此基础上添加OK
和Cancel
按钮,如下图所示 -
经过测试发现,不管
MessageDialog.xaml
中写了什么内容,最终都不会呈现在界面上(chatgpt还给了一系列的错误方案,例如 放一个 名为 PART_Host 的ContentControl)。 -
遇到解决不了的问题还是看源码确认下:
public void ShowDialog(string name, IDialogParameters parameters, DialogCallback callback) { parameters ??= new DialogParameters(); var isModal = parameters.TryGetValue<bool>(KnownDialogParameters.ShowNonModal, out var show) ? !show : true; var windowName = parameters.TryGetValue<string>(KnownDialogParameters.WindowName, out var wName) ? wName : null; IDialogWindow dialogWindow = CreateDialogWindow(windowName); ConfigureDialogWindowEvents(dialogWindow, callback); ConfigureDialogWindowContent(name, dialogWindow, parameters); ShowDialogWindow(dialogWindow, isModal); } protected virtual void ConfigureDialogWindowContent(string dialogName, IDialogWindow window, IDialogParameters parameters) { ConfigureDialogWindowProperties(window, dialogContent, viewModel); } protected virtual void ConfigureDialogWindowProperties(IDialogWindow window, FrameworkElement dialogContent, IDialogAware viewModel) { var windowStyle = Dialog.GetWindowStyle(dialogContent); if (windowStyle != null) window.Style = windowStyle; window.Content = dialogContent; // window.DataContext = viewModel; //we want the host window and the dialog to share the same data context if (window.Owner == null) window.Owner = Application.Current?.Windows.OfType<Window>().FirstOrDefault(x => x.IsActive); }
-
从以上代码可以看出
window.Content = dialogContent;
,直接将window的Content
替换,所以不管我们在.xaml
中写了什么内容,都会被替换。 -
那么只能从模板上想办法了,直接修改
MessageVDialog
的模板<Window.Template> <ControlTemplate TargetType="Window"> <Border Background="White"> <Grid> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <ContentControl Content="{TemplateBinding Content}" /> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="1" Margin="20"> <Button Content="OK" Width="100" Click="OKButton_Click" /> <Button Content="Cancel" Margin="20 0 0 0" Width="100" Click="CancelButton_Click" /> </StackPanel> </Grid> </Border> </ControlTemplate> </Window.Template>
private void OKButton_Click(object sender, RoutedEventArgs e) { Result = new DialogResult(ButtonResult.OK); this.DialogResult = true; } private void CancelButton_Click(object sender, RoutedEventArgs e) { Result = new DialogResult(ButtonResult.Cancel); this.DialogResult = false; }
-
运行效果: