San
San

Reputation: 1837

Popup always stays on top

I've WPF application which has one Main window on which I'm opening a Popup window. The problem I'm facing is the Popup window always stays on top. If I open some other application(any windows application) the main window goes into background but the Popup windows remain on top.However if I minimize the Mainwindow the Popup also minimizes.

Below image shows the problem. The PopUp window is appearing on top of Notepad application

Please help on overcoming this issue.

Update:

I am opening the Popup as below

 myPopup.IsOpen = true;

Upvotes: 23

Views: 35937

Answers (8)

Willy
Willy

Reputation: 10650

By default popups were designed to behaves as you comment, to be topmost always. Altering this behavior using hacks or things like that will complicate your life since you will have to lead with some other problems that for sure will arise.

Anyway, too late, but may be this can help you or others: https://chriscavanagh.wordpress.com/2008/08/13/non-topmost-wpf-popup/

Note that this has some issues.... read all the comments published there. Among other issues, it makes all childs to be non-topmost so comboboxes are affected. Comboboxes will have problems with it as they rely on having a topmost popup for when they are drop down, so if you have any combobox inside your popup it will break.

Also there are other problems related to the popup position, when you resize and then move the main window where the popup is it, popup remains in the same position.

People there are proposing some approaches for these issues. I don't know if all are resolved but you can give it a try or try to resolve them if it is up to you.

Other people trying to face with this are explaining their proposals here also (although none of them seems to be the perfect solution, it looks like there is not a perfect one, all of them have drawnbacks, but again as I have said, trying to alter the default behavior for which a thing was designed for will lead into continuous problems) : WPF Popup ZOrder

Upvotes: 0

Learner
Learner

Reputation: 21

This solved my problem.

PopupForm pf = new PopupForm();
pf.Owner = this;
pf.Topmost = false;
pf.ShowDialog()

Upvotes: 1

Mohsen
Mohsen

Reputation: 4266

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Interop;

/// <summary>
/// Popup with code to not be the topmost control
/// </summary>
public class NonTopmostPopup : Popup
{
    /// <summary>
    /// Is Topmost dependency property
    /// </summary>
    public static readonly DependencyProperty IsTopmostProperty = DependencyProperty.Register("IsTopmost", typeof(bool), typeof(NonTopmostPopup), new FrameworkPropertyMetadata(false, OnIsTopmostChanged));

    private bool? _appliedTopMost;
    private bool _alreadyLoaded;
    private Window _parentWindow;

    /// <summary>
    /// Get/Set IsTopmost
    /// </summary>
    public bool IsTopmost
    {
        get { return (bool)GetValue(IsTopmostProperty); }
        set { SetValue(IsTopmostProperty, value); }
    }

    /// <summary>
    /// ctor
    /// </summary>
    public NonTopmostPopup()
    {
        Loaded += OnPopupLoaded;
        Unloaded += OnPopupUnloaded;
    }


    void OnPopupLoaded(object sender, RoutedEventArgs e)
    {
        if (_alreadyLoaded) 
            return;

        _alreadyLoaded = true;

        if (Child != null)
        {
            Child.AddHandler(PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(OnChildPreviewMouseLeftButtonDown), true);
        }

        _parentWindow = Window.GetWindow(this);

        if (_parentWindow == null) 
            return;

        _parentWindow.Activated += OnParentWindowActivated;
        _parentWindow.Deactivated += OnParentWindowDeactivated;
    }

    private void OnPopupUnloaded(object sender, RoutedEventArgs e)
    {
        if (_parentWindow == null)
            return;
        _parentWindow.Activated -= OnParentWindowActivated;
        _parentWindow.Deactivated -= OnParentWindowDeactivated;
    }

    void OnParentWindowActivated(object sender, EventArgs e)
    {
        Debug.WriteLine("Parent Window Activated");
        SetTopmostState(true);
    }

    void OnParentWindowDeactivated(object sender, EventArgs e)
    {
        Debug.WriteLine("Parent Window Deactivated");

        if (IsTopmost == false)
        {
            SetTopmostState(IsTopmost);
        }
    }

    void OnChildPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        Debug.WriteLine("Child Mouse Left Button Down");

        SetTopmostState(true);

        if (!_parentWindow.IsActive && IsTopmost == false)
        {
            _parentWindow.Activate();
            Debug.WriteLine("Activating Parent from child Left Button Down");
        }
    }

    private static void OnIsTopmostChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        var thisobj = (NonTopmostPopup)obj;

        thisobj.SetTopmostState(thisobj.IsTopmost);
    }

    protected override void OnOpened(EventArgs e)
    {
        SetTopmostState(IsTopmost);
        base.OnOpened(e);
    }

    private void SetTopmostState(bool isTop)
    {
        // Don’t apply state if it’s the same as incoming state
        if (_appliedTopMost.HasValue && _appliedTopMost == isTop)
        {
            return;
        }

        if (Child == null) 
            return;

        var hwndSource = (PresentationSource.FromVisual(Child)) as HwndSource;

        if (hwndSource == null) 
            return;
        var hwnd = hwndSource.Handle;

        RECT rect;

        if (!GetWindowRect(hwnd, out rect)) 
            return;

        Debug.WriteLine("setting z-order " + isTop);

        if (isTop)
        {
            SetWindowPos(hwnd, HWND_TOPMOST, rect.Left, rect.Top, (int)Width, (int)Height, TOPMOST_FLAGS);
        }
        else
        {
            // Z-Order would only get refreshed/reflected if clicking the
            // the titlebar (as opposed to other parts of the external
            // window) unless I first set the popup to HWND_BOTTOM
            // then HWND_TOP before HWND_NOTOPMOST
            SetWindowPos(hwnd, HWND_BOTTOM, rect.Left, rect.Top, (int)Width, (int)Height, TOPMOST_FLAGS);
            SetWindowPos(hwnd, HWND_TOP, rect.Left, rect.Top, (int)Width, (int)Height, TOPMOST_FLAGS);
            SetWindowPos(hwnd, HWND_NOTOPMOST, rect.Left, rect.Top, (int)Width, (int)Height, TOPMOST_FLAGS);
        }

        _appliedTopMost = isTop;
    }

    #region P/Invoke imports & definitions
    #pragma warning disable 1591 //Xml-doc
    #pragma warning disable 169 //Never used-warning
    // ReSharper disable InconsistentNaming
    // Imports etc. with their naming rules

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT

    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

    [DllImport("user32.dll")]
    private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X,
    int Y, int cx, int cy, uint uFlags);

    static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
    static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
    static readonly IntPtr HWND_TOP = new IntPtr(0);
    static readonly IntPtr HWND_BOTTOM = new IntPtr(1);

    private const UInt32 SWP_NOSIZE = 0x0001;
    const UInt32 SWP_NOMOVE = 0x0002;
    const UInt32 SWP_NOZORDER = 0x0004;
    const UInt32 SWP_NOREDRAW = 0x0008;
    const UInt32 SWP_NOACTIVATE = 0x0010;

    const UInt32 SWP_FRAMECHANGED = 0x0020; /* The frame changed: send WM_NCCALCSIZE */
    const UInt32 SWP_SHOWWINDOW = 0x0040;
    const UInt32 SWP_HIDEWINDOW = 0x0080;
    const UInt32 SWP_NOCOPYBITS = 0x0100;
    const UInt32 SWP_NOOWNERZORDER = 0x0200; /* Don’t do owner Z ordering */
    const UInt32 SWP_NOSENDCHANGING = 0x0400; /* Don’t send WM_WINDOWPOSCHANGING */

    const UInt32 TOPMOST_FLAGS = 
        SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSENDCHANGING;

    // ReSharper restore InconsistentNaming
    #pragma warning restore 1591
    #pragma warning restore 169
    #endregion
}

Upvotes: 35

Sascha Hennig
Sascha Hennig

Reputation: 2572

Create your PopUp window modal to the parent control only, as demonstrated by Billy Holli and Brad Leach. That way it will stay on top of the application/window which opened the popup control, but will not stay on top of other windows/applications any longer.

Upvotes: -1

Jefim
Jefim

Reputation: 3077

H.B. is correct - WPF Popup control was not intended do be not top-most. On the other hand - check out the following blog post on using user32 for achieving your goal: http://chriscavanagh.wordpress.com/2008/08/13/non-topmost-wpf-popup/

Upvotes: 11

brunnerh
brunnerh

Reputation: 185300

Popups do - as far as i know - not suppot such a behavior, their intended usage is for ComboxBox-dropdowns and the like as far as i can tell. To realize something like that you can use a normal Window and set its Owner to the main window on which it should be dependent. This will cause the popup-window to stay on top of its owner & to minimize together with the owner.

e.g.

public class ChildWindow: Window
{
    public ChildWindow(Window owner)
    {
        this.Owner = owner;
    }
}
var popup = new ChildWindow(mainWindow);
popup.Show();

(Windows cannot be re-opened once closed, so to reuse a window you just have to Hide() it when the user tries to close it (handle Closing event and cancel using event args))

Upvotes: 15

Samich
Samich

Reputation: 30175

Check the Window.Topmost property whitch is indicates that window should be always on top.

PopupWindow wnd = new PopupWindow();
wnd.ShowDialog();

Upvotes: 0

Dominik
Dominik

Reputation: 3372

Are you creating the PopUp using the WPF control? The way this control paints popup leads to the behaviour you are describing. Consider creating a new Window showing the content you´d like to display.

Upvotes: 0

Related Questions