WPF+PRISM 如何使弹出 window owner as main window

WPF+PRISM How to make the popup window owner as main window

我无法将 Popup window 的所有者设置为 Application Main window。

这是我做的。

  1. 创建了带有自定义弹出窗口的 Main Window。Window。

    <Window x:Class="MainWindow"
        ...
    
        <Window.Resources>
            <Style x:Key="MessageWindowStyle" TargetType="{x:Type Window}">
                <Setter Property="Background" Value="Transparent" />
                <Setter Property="WindowStyle" Value="None" />
                <Setter Property="ResizeMode" Value="NoResize" />
                <Setter Property="BorderThickness" Value="1" />
                <Setter Property="SnapsToDevicePixels" Value="True" />
                <Setter Property="ShowInTaskbar" Value="False"/>
                <Setter Property="AllowsTransparency" Value="True"/>
            </Style>
        </Window.Resources>
    
        <i:Interaction.Triggers>
            <interactionRequest:InteractionRequestTrigger SourceObject="{Binding MessageRequest, Mode=OneWay}">
                <interactionRequest:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True" WindowStyle="{StaticResource MessageWindowStyle}" >
                    <interactionRequest:PopupWindowAction.WindowContent>
                        <controls:PageCustomPopup />
                    </interactionRequest:PopupWindowAction.WindowContent>
                </interactionRequest:PopupWindowAction>
            </interactionRequest:InteractionRequestTrigger>
        </i:Interaction.Triggers>
    
        ...
    </Window>
    
  2. PageCustomPopup.xaml

这是弹出窗口 window 的基本 xaml。

    <UserControl x:Class="PageCustomPopup"
        ...
    </UserControl>
  1. PageCustomPopup.xaml.cs

在此页面代码隐藏中,我尝试在加载弹出 window 时设置父级。但它抛出异常。

    public partial class PageCustomPopup : UserControl,  InteractionRequestAware, INotifyPropertyChanged
    {
        public PageCustomPopup()
        {
            Loaded += (sender, args) =>
            {
                try
                {
                    var parentWindow = this.Parent as Window;
                    if (parentWindow != null)
                    {
                        // This line fails with "Cannot set the Owner after the window is displayed."
                        //parentWindow.Owner = Application.Current.MainWindow;

                        // First, default to the main window's dimensions
                        parentWindow.Width = Application.Current.MainWindow.Width;
                        parentWindow.Height = Application.Current.MainWindow.Height;
                        parentWindow.Left = Application.Current.MainWindow.Left;
                        parentWindow.Top = Application.Current.MainWindow.Top;
                    }
                }
            }
        }
    }
  1. MainWindow 后面的代码。

    public InteractionRequest<Notification> MessageRequest { get; private set; }
    
    public MainWindow()
    {
        ...
    
        MessageRequest = new InteractionRequest<Notification>();
    
        ...
    }
    
    void Button_OnClick(object sender, EventArgs e)
    {
        MessageRequest.Raise(new Notification(){ Title = "Title Text", Content = "Message to Display"});
    }
    

显示自定义弹出窗口 window 时,它会正确显示在主 window 的中心。

但问题是,当所有的windows都最小化后,如果点击任务栏上的应用程序图标,会显示应用程序主window,并且无法正常工作。不能select任何东西。

弹出窗口 window 已隐藏,无法显示在前面。

将 Popup window 放在前面的唯一方法是使用 "Alt+Tab" 键。

我的问题是,如何将自定义弹出窗口 window 所有者设置为 Application.Current.MainWindow? 因此,通过 selecting 任务栏图标或 Alt+Tab,显示 Mainwindow 和弹出窗口 window。

如错误所述,您将 属性 设置得太晚了。您在 Loaded 事件中设置它,因此 window 已经加载。您需要在显示 window 之前设置它。正如您所知,这已在 Prism for WPF 的最新预览版中得到修复。

如果您想升级 NuGets 以使用最新的预览版。以下是修复列表:

https://github.com/PrismLibrary/Prism/wiki/Release-Notes--Jan-10,-2016#prism-for-wpf-611-pre2

与此同时,如果您不想使用预览版,您可以自己实现,派生自 PopupWindowAction:

public class PopupChildWindowAction : PopupWindowAction
{
    public static readonly DependencyProperty WindowOwnerProperty = DependencyProperty.Register(
        "WindowOwner", typeof (Window), typeof (PopupChildWindowAction), new PropertyMetadata(default(Window)));

    public Window WindowOwner
    {
        get { return (Window) GetValue(WindowOwnerProperty); }
        set { SetValue(WindowOwnerProperty, value); }
    }

    protected override Window GetWindow(INotification notification)
    {
        Window wrapperWindow;
        if (this.WindowContent != null)
        {
            wrapperWindow = this.CreateWindow();
            if (wrapperWindow == null)
                throw new NullReferenceException("CreateWindow cannot return null");
            wrapperWindow.Owner = WindowOwner;
            wrapperWindow.DataContext = (object)notification;
            wrapperWindow.Title = notification.Title;
            this.PrepareContentForWindow(notification, wrapperWindow);
        }
        else
            wrapperWindow = this.CreateDefaultWindow(notification);
        if (this.WindowStyle != null)
            wrapperWindow.Style = this.WindowStyle;
        return wrapperWindow;
    }
}

用法:

<i:Interaction.Triggers>
    <interactionRequest:InteractionRequestTrigger SourceObject="{Binding MessageRequest, Mode=OneWay}">
        <local:PopupChildWindowAction IsModal="True" CenterOverAssociatedObject="True" WindowStyle="{StaticResource MessageWindowStyle}" 
                                      WindowOwner="{Binding ElementName=MyMainWindow}">
            <interactionRequest:PopupWindowAction.WindowContent>
                <local:PageCustomPopup />
            </interactionRequest:PopupWindowAction.WindowContent>
        </local:PopupChildWindowAction>
    </interactionRequest:InteractionRequestTrigger>
</i:Interaction.Triggers>

刚刚更新@Szabolcs 的回答。实际上,我发现有些功能在我的 PRISM 版本中不可用。此外,微不足道的是我的对话框的样式没有保留,所以这段代码解决了我的问题。

protected override Window GetWindow(INotification notification)
        {
            Window wrapperWindow;
            if (this.WindowContent != null)
            {
                wrapperWindow = new Window();
                if (wrapperWindow == null)
                    throw new NullReferenceException("CreateWindow cannot return null");
                wrapperWindow.Owner = WindowOwner;
                wrapperWindow.DataContext = (object)notification;
                wrapperWindow.Title = notification.Title;
                this.PrepareContentForWindow(notification, wrapperWindow);
            }
            else
                wrapperWindow = this.CreateDefaultWindow(notification);
            return wrapperWindow;
        }

以下一组行未编译,因为(可能是由于不同版本的 PRISM 组件)。所以我用 wrapperWindow = new Window() 初始化并在行为 class 的 Loaded 事件上应用样式如下。

AssociatedObject.Loaded += (sender, e) =>
            {
                // get the window
                Window window = Window.GetWindow((UserControl)sender);
                if (window != null)
                {
                    window.WindowStyle = WindowStyle.None;
                    window.ResizeMode = ResizeMode.NoResize;
                    window.Background = Brushes.Transparent;
                    window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
                }
            };

我不得不更改 xaml 部分,因为我的主要 windnow 元素名称不可用

<presentBehaviors:PopupChildWindowAction IsModal="False" CenterOverAssociatedObject="True" WindowOwner="{Binding RelativeSource={RelativeSource AncestorType=Window}}">