Prism IDialogService 显示非模态对话框充当模态
Prism IDialogService Show Non-Modal Dialog acts as Modal
在 WPF Prism 7.2 中,我遵循了 IDialogService
instructions shown here。
我有一个 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
按预期运行。
它实际上不是模态的,只是最上面的window。使用 ShowDialog
方法显示模态对话框,它不仅会出现在最顶部 window,而且还会禁止用户与其所有者进行任何交互 window,直到被关闭。
一个对话框位于另一个 window 之上的原因是它有一个所有者 window 分配给它的 Owner
属性。默认情况下,Prism 将始终将应用程序中的第一个 active window 指定为对话框的所有者,除非您设置了一个 not null 的所有者 明确在对话主机上 window。
请参阅 GitHub 上 DialogService
的实施以供参考。此行设置对话框的 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);
}
创建从 ICustomDialogService
派生的类型 CustomDialogService
并从 GitHub 复制 original implementation。通过将参数传递给 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
属性 的自定义对话主机 window 或其他 hack,但我认为创建自定义对话服务是最干净的接近这里。
在 WPF Prism 7.2 中,我遵循了 IDialogService
instructions shown here。
我有一个 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
按预期运行。
它实际上不是模态的,只是最上面的window。使用 ShowDialog
方法显示模态对话框,它不仅会出现在最顶部 window,而且还会禁止用户与其所有者进行任何交互 window,直到被关闭。
一个对话框位于另一个 window 之上的原因是它有一个所有者 window 分配给它的 Owner
属性。默认情况下,Prism 将始终将应用程序中的第一个 active window 指定为对话框的所有者,除非您设置了一个 not null 的所有者 明确在对话主机上 window。
请参阅 GitHub 上 DialogService
的实施以供参考。此行设置对话框的 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);
}
创建从 ICustomDialogService
派生的类型 CustomDialogService
并从 GitHub 复制 original implementation。通过将参数传递给 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
属性 的自定义对话主机 window 或其他 hack,但我认为创建自定义对话服务是最干净的接近这里。