1
votes

I am having trouble setting the owner of Popup window to Application Main window.

Here what I did.

  1. Created a Main Window with custom 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

This is basic xaml for the popup window.

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

In this page code-behind, I tried to set the parent, when the popup window is loaded. But it throws exception.

    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 code behind.

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

When the Custom popup window is displayed, it shows correctly in the center of the main window.

But the issue is, when all the windows are minimized, if the Application icon on the taskbar is clicked, the Application main window is displayed, and inavtive. Cannot select anything.

The popup window is hidden and cannot bring to front.

The only way to bring the Popup window in front, is using "Alt+Tab" keys.

My question is, how to set the Custom popup window owner to Application.Current.MainWindow? So that, by selecting taskbar icon or Alt+Tab, displays both Mainwindow and popup window.

3

3 Answers

1
votes

As the error says, you are setting the property too late. You are setting it in the Loaded event, so the window has already loaded. You need to set this before the window is shown. Just so you know, this has already been fixed in the latest preview of Prism for WPF.

If you want to upgrade your NuGets to use the latest preview that is. Here is a list of fixes:

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

1
votes

In the meantime if you don't want to use a preview version, you can just implement this yourself deriving from 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;
    }
}

Usage:

<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
votes

Just updating @Szabolcs's Answer. Actually, I found some of the functions are not available in my PRISM's version. Also, trivial thing is that my dialog's style was not preserved so this code solved my problem.

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

Following set of lines was not compiling because (may be due to different version of PRISM's asselblies). So I initialized with wrapperWindow = new Window() and applied style on Loaded event in behavior class as follows.

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

I had to change the xaml part also because my main windnow element name was not available

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