更改 Prism DialogWindow 的所有者

1 c# wpf prism modal-dialog mvvm

我已经使用 MVVM 在 WPF 中实现了新功能IDialogService。我的对话框工作正常,但当我在前台打开另一个窗口时,该对话框将出现在该窗口的中心。

我想要实现的是,对话框始终位于主窗口的中心。这可以通过将(其类型和我创建的对话框Owner的)属性设置为 来应用。DialogWindowWindowParentUserControlApplication.Current.MainWindow

我现在发现,可以更改 的样式,DialogWindow如下所示。但我认为没有任何可能以Owner这种方式改变财产。

Owner我已经尝试通过访问CodeBehindParent中的来设置属性UserControl。但它要么为 null ( OnInitialized),要么无法更改,因为“DialogWindow已显示”( OnLoaded/ OnApplyTemplate)。

您对如何解决这个问题有什么建议吗?

tha*_*guy 6

Prism 对话框服务默认将第一个活动窗口设置为对话框的所有者。这就是它的实施方式。有多种方法可以将主窗口设置为所有者,或多或少的努力和不同的约束,但它需要一些自定义。只花了一个月的时间就写好了。

替换对话框窗口

Window您可以通过从 派生并实现来定义新的对话框宿主窗口IDialogWindow

public class DialogWindow : Window, IDialogWindow
{
   public DialogWindow()
   {
      Owner = System.Windows.Application.Current.MainWindow;
      WindowStartupLocation = WindowStartupLocation.CenterOwner;
   }

   public IDialogResult Result { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后将其注册到您的容器中。这样,所有对话框都将位于主窗口的中心。

containerRegistry.Register<IDialogWindow, DialogWindow>();
Run Code Online (Sandbox Code Playgroud)

您还可以在对话框窗口样式中设置窗口启动位置,而不是在对话框窗口类中设置。

<prism:Dialog.WindowStyle>
   <Style TargetType="Window">
      <Setter Property="prism:Dialog.WindowStartupLocation" Value="CenterOwner" />
   </Style>
</prism:Dialog.WindowStyle>
Run Code Online (Sandbox Code Playgroud)

这种方法在 Prism 的更高版本中可能会更有趣,它可能允许注册多个命名对话框窗口。然后,您可以在特殊情况下使用自定义窗口,否则使用默认窗口。

自定义对话服务

您只需DialogService 从 Prism 复制实施并对其进行调整以满足您的需求。在ConfigureDialogWindowProperties更改设置所有者窗口的行中。


window.Owner = System.Windows.Application.Current.Windows.OfType<Window>().FirstOrDefault(x => x.IsActive);
Run Code Online (Sandbox Code Playgroud)

将默认活动窗口替换为主窗口。

window.Owner = System.Windows.Application.Current.MainWindow;
Run Code Online (Sandbox Code Playgroud)

不要忘记在容器中注册自定义对话框服务以覆盖默认的对话框服务。

containerRegistry.RegisterSingleton<IDialogService, CustomDialogService>();
Run Code Online (Sandbox Code Playgroud)

具有附加属性的自定义对话框服务

如果您需要更多自定义行为,请考虑使用附加属性使该下级逻辑可参数化,您可以在用户控件上设置这些属性并在自定义对话框服务中读取这些属性。这是最灵活的方法,但也是最需要付出努力的方法。它允许单独定制每个对话框。

public class WindowOwnerAttachedProperties
{
   public static readonly DependencyProperty IsMainWindowOwnerProperty = DependencyProperty.RegisterAttached("IsMainWindowOwner", typeof(bool), typeof(WindowOwnerAttachedProperties), new PropertyMetadata(false));

   public static bool GetIsMainWindowOwner(DependencyObject dependencyObject)
   {
      return (bool)dependencyObject.GetValue(IsMainWindowOwnerProperty);
   }

   public static void SetIsMainWindowOwner(DependencyObject dependencyObject, Window value)
   {
      dependencyObject.SetValue(IsMainWindowOwnerProperty, value);
   }
}
Run Code Online (Sandbox Code Playgroud)

在对话框用户控件中设置附加属性。

public class DialogWindow : Window, IDialogWindow
{
   public DialogWindow()
   {
      Owner = System.Windows.Application.Current.MainWindow;
      WindowStartupLocation = WindowStartupLocation.CenterOwner;
   }

   public IDialogResult Result { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

根据自定义对话框服务中的上述附加属性设置窗口所有者。

if (window.Owner == null && WindowOwnerAttachedProperties.GetIsMainWindowOwner(dialogContent))
   window.Owner = System.Windows.Application.Current.MainWindow;
else if (window.Owner == null)
   window.Owner = System.Windows.Application.Current.Windows.OfType<Window>().FirstOrDefault(x => x.IsActive);
Run Code Online (Sandbox Code Playgroud)

这使您可以选择使用默认行为以实现向后兼容性,或将主窗口单独设置为每个对话框视图的所有者。