【问题标题】:WPF+PRISM How to make the popup window owner as main windowWPF+PRISM 如何使弹出窗口所有者为主窗口
【发布时间】:2016-06-10 04:44:56
【问题描述】:

我无法将弹出窗口的所有者设置为应用程序主窗口。

这就是我所做的。

  1. 使用自定义 PopupWindow 创建了一个主窗口。

    <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

这是弹出窗口的基本 xaml。

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

在此页面代码隐藏中,我尝试在加载弹出窗口时设置父级。但它会引发异常。

    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"});
    }
    

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

但问题是,当所有窗口最小化时,如果单击任务栏上的应用程序图标,则会显示应用程序主窗口,并且不可用。无法选择任何内容。

弹出窗口是隐藏的,不能放在前面。

将弹出窗口置于前面的唯一方法是使用“Alt+Tab”键。

我的问题是,如何将自定义弹出窗口所有者设置为 Application.Current.MainWindow? 这样,通过选择任务栏图标或 Alt+Tab 即可同时显示主窗口和弹出窗口。

【问题讨论】:

    标签: wpf modal-dialog prism popupwindow


    【解决方案1】:

    正如错误所说,您设置属性为时已晚。您在 Loaded 事件中设置它,因此窗口已经加载。您需要在显示窗口之前进行设置。请注意,此问题已在 Prism for WPF 的最新预览版中得到修复。

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

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

    【讨论】:

    • 感谢布赖恩的更新。我无法更新 6.1.1 的解决方案。但我尝试了 Szabolcs 的解决方案。效果很好。
    • Brian,我使用的是 Nuget 的 6.2,但遇到了类似的问题。当我查看实时属性窗口时,我的对话框中没有设置所有者。我可能会就此提出一个新问题。
    【解决方案2】:

    同时,如果您不想使用预览版,您可以自己实现,从 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>
    

    【讨论】:

      【解决方案3】:

      只是更新@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() 进行了初始化,并在行为类中的 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 部分,因为我的主要 windows 元素名称不可用

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

      【讨论】:

        猜你喜欢
        • 2021-08-25
        • 1970-01-01
        • 2011-02-05
        • 1970-01-01
        • 1970-01-01
        • 2010-11-06
        • 2012-07-15
        • 2017-09-06
        • 1970-01-01
        相关资源
        最近更新 更多