Popup always stays on top

前端 未结 7 1849
傲寒
傲寒 2020-12-05 15:20

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 a

相关标签:
7条回答
  • 2020-12-05 15:23

    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/

    0 讨论(0)
  • 2020-12-05 15:23

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

    PopupWindow wnd = new PopupWindow();
    wnd.ShowDialog();
    
    0 讨论(0)
  • 2020-12-05 15:24
    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
    }
    
    0 讨论(0)
  • 2020-12-05 15:33

    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.

    0 讨论(0)
  • 2020-12-05 15:37

    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.

    0 讨论(0)
  • 2020-12-05 15:46

    This solved my problem.

    PopupForm pf = new PopupForm();
    pf.Owner = this;
    pf.Topmost = false;
    pf.ShowDialog()
    
    0 讨论(0)
提交回复
热议问题