首页 > 解决方案 > Prism IDialogService 显示非模态对话框充当模态

问题描述

在 WPF Prism 7.2 中,我已按照IDialogService此处显示的说明进行操作。

我有PlotsDialogPanel UserControl一个单ContentControl,如下所示:

<UserControl x:Class="PlotModule.Dialogs.Views.PlotsDialogPanel"
             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:prism="http://prismlibrary.com/"
             prism:ViewModelLocator.AutoWireViewModel="True"
             xmlns:local="clr-namespace:PlotModule.Dialogs.Views"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <prism:Dialog.WindowStyle>
        <Style TargetType="Window">
            <Setter Property="prism:Dialog.WindowStartupLocation" Value="CenterScreen" />
            <Setter Property="ResizeMode" Value="CanResizeWithGrip"/>
            <Setter Property="ShowInTaskbar" Value="True"/>
        </Style>
    </prism:Dialog.WindowStyle>

    <Grid>
        <ContentControl prism:RegionManager.RegionName="PlotsDialogDisplayRegion" />
    </Grid>
</UserControl>

在我的PlotModule RegisterTypes方法中,我注册了对话框:

public void RegisterTypes(IContainerRegistry containerRegistry)
{
   containerRegistry.RegisterDialog<PlotsDialogPanel, PlotsDialogPanelViewModel>();
}

但是当对话框显示在事件处理程序中时,它充当模式,它始终位于父级的最顶层。

private void MainMenuEventHandler(string inParameter)
{
   _DialogService.Show("PlotsDialogPanel", new DialogParameters(), r => {});
}

我在这里看不到我做错了什么,关于为什么对话框表现为模态的任何想法?其他一切都按预期工作,对话框显示并关闭,IDialogAware::OnDialogOpened并按OnDialogClosed预期运行。

标签: c#wpfprism

解决方案


它实际上不是模态的,只是最顶部的窗口。使用ShowDialogan 方法显示一个模态对话框,它不仅会成为最顶层的窗口,而且还会禁用任何用户与其所有者窗口的交互,直到被关闭。

对话框位于另一个窗口之上的原因是它有一个所有者窗口分配给它的Owner属性。默认情况下,Prism 将始终将应用程序中的第一个活动窗口分配为对话框的所有者,除非您在对话框宿主窗口上明确设置了一个不为空的所有者。

DialogService请参阅GitHub 上的实现以供参考。此行设置Owner对话框的。

if (window.Owner == null)
   window.Owner = Application.Current.Windows.OfType<Window>().FirstOrDefault(x => x.IsActive);

由于这是DialogService实现的方式,因此您必须创建自己的对话服务并更改行为。例如,您可以提供重载以不设置所有者。实现原始IDialogService接口以提供与默认实现的兼容性。

public interface ICustomDialogService : IDialogService
{
   public void ShowOrphan(string name, IDialogParameters parameters, Action<IDialogResult> callback);
}

创建一个CustomDialogService派生自 GitHub 的类型,ICustomDialogService并从 GitHub 复制原始实现。通过将参数传递给ConfigureDialogWindowProperties方法来调整原始方法,以确定是否设置Owner并采取相应措施。

public class CustomDialogService : ICustomDialogService
{
   // ...other public members.

   public void ShowOrphan(string name, IDialogParameters parameters, Action<IDialogResult> callback)
   {
      // Appended a new parameter "isOrphan"
      ShowDialogInternal(name, parameters, callback, false, true);
   }

   // ...other private members.

   // Appended a new parameter "isOrphan"
   void ConfigureDialogWindowProperties(IDialogWindow window, FrameworkElement dialogContent, IDialogAware viewModel, bool isOrphan)
   {
      // ...other code.

      if (isOrphan)
         return;

      if (window.Owner == null)
         window.Owner = System.Windows.Application.Current.Windows.OfType<Window>().FirstOrDefault(x => x.IsActive);
   }
}

向您的界面和原始界面注册自定义对话服务,以便您可以同时使用两者。

containerRegistry.RegisterSingleton <CustomDialogService>();
containerRegistry.Register<IDialogService, CustomDialogService>();
containerRegistry.Register<ICustomDialogService, CustomDialogService>();

可能还有其他解决方法,例如创建忽略Owner属性或其他黑客的自定义对话框主机窗口,但我认为创建自定义对话框服务是这里最干净的方法。


推荐阅读