2016-02-26 185 views
1

我無法將彈出窗口的所有者設置爲應用程序主窗口。WPF + PRISM如何將彈出窗口的所有者作爲主窗口

在這裏,我做了什麼。

  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> 
  • 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; 
            } 
           } 
          } 
         } 
        } 
    
  • 主窗口後面的代碼。

    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"}); 
    } 
    
  • 當顯示自定義彈出窗口,它正確地顯示在主窗口的中心。

    但問題是,當所有的窗口都被最小化時,如果點擊任務欄上的應用程序圖標,應用程序主窗口將顯示出來並顯示。無法選擇任何東西。

    彈出式窗口被隱藏起來,不能放到前面。

    將Popup窗口放在前面的唯一方法是使用「Alt + Tab」鍵。

    我的問題是,如何將自定義彈出窗口的所有者設置爲Application.Current.MainWindow? 這樣,通過選擇任務欄圖標或Alt + Tab,顯示主窗口和彈出窗口。

    回答

    1

    在,如果你不希望使用預覽版的同時,你可以自己實現從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> 
    
    +0

    謝謝Szabolcs !!!。此解決方案完美運作。 – ATati

    +0

    @ATati你可以請upvote並接受答案。 –

    1

    正如錯誤所述,您設置的屬性太晚了。你在Loaded事件中設置它,所以窗口已經加載。您需要在顯示窗口之前設置它。只是你知道,這已經在最新的Prism for WPF預覽中得到了修復。

    如果你想升級你的NuGets使用最新的預覽。以下是修復列表:

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

    +0

    感謝布賴恩進行更新。我無法更新6.1.1的解決方案。但我嘗試了Szabolcs的解決方案。這工作完美。 – ATati

    +0

    布賴恩,我使用6.2從Nuget但有類似的問題。當我查看實時屬性窗口時,我的對話框中沒有設置所有者。我可能會在這個問題上引發一個新的問題。 – Gusdor

    0

    剛剛更新@索博爾奇的回答:。實際上,我發現我的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的asselblies的)。所以我用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一部分,因爲我的主要windnow元素名稱不可用

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