Popup总是保持领先

我有一个WPF应用程序,它有一个主窗口,我打开一个弹出窗口。 我面临的问题是弹出窗口总是保持在最顶层。 如果我打开一些其他应用程序( 任何Windows应用程序 ),主窗口进入后台,但弹出窗口仍然在顶部。但是,如果我最小化主窗口,弹出窗口也最小化。

下图显示了问题。 PopUp窗口出现在记事本应用程序的顶部

请帮助克服这个问题。

更新:

我打开Popup如下

myPopup.IsOpen = true; 

Popups – 据我所知 – 不支持这样的行为,据他所知,它们的用途是针对ComboxBox -downdownns等。 要实现类似的function,您可以使用普通Window并将其Owner设置为它应该依赖的主窗口。 这将导致弹出窗口保持在其所有者之上并与所有者一起最小化。

例如

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

(一旦关闭,Windows无法重新打开,因此当用户尝试关闭它时,重用一个窗口,你只需要Hide()它(处理Closing事件并使用事件args取消))

 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; ///  /// Popup with code to not be the topmost control ///  public class NonTopmostPopup : Popup { ///  /// Is Topmost dependency property ///  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; ///  /// Get/Set IsTopmost ///  public bool IsTopmost { get { return (bool)GetValue(IsTopmostProperty); } set { SetValue(IsTopmostProperty, value); } } ///  /// ctor ///  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 } 

HB是正确的 – WPF Popup控件并不是最重要的。 另一方面 – 查看以下有关使用user32实现目标的博文: http : //chriscavanagh.wordpress.com/2008/08/13/non-topmost-wpf-popup/

您是否使用WPF控件创建PopUp? 此控件绘制弹出窗口的方式会导致您描述的行为。 考虑创建一个新窗口,显示您想要显示的内容。

检查Window.Topmost属性Window.Topmost表示窗口应始终位于顶部。

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

如Billy Holli和Brad Leach所示,仅为父控件创建PopUp窗口模态。 这样它将保持打开弹出控件的应用程序/窗口的顶部,但不会再停留在其他窗口/应用程序之上。

这解决了我的问题。

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