Popup 解决StayOpen=true时,置顶的问题

Posted 唐宋元明清的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Popup 解决StayOpen=true时,置顶的问题相关的知识,希望对你有一定的参考价值。

/// <summary>
/// 解决StayOpen=true时,永远置顶问题的Popup控件
/// </summary>
public class EasiNotePopup : Popup
{
public static readonly DependencyProperty IsTopmostProperty = DependencyProperty.Register("IsTopmost", typeof(bool), typeof(EasiNotePopup), new FrameworkPropertyMetadata(false, OnIsTopmostChanged));

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

public bool IsTopmost
{
get { return (bool)GetValue(IsTopmostProperty); }
set { SetValue(IsTopmostProperty, value); }
}

/// <summary>
/// ctor
/// </summary>
public EasiNotePopup()
{
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)
{
SetTopmostState(true);
}

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

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

void OnChildPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{

SetTopmostState(true);

if (!_parentWindow.IsActive && IsTopmost == false)
{
_parentWindow.Activate();
}
}

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

thisobj.SetTopmostState(thisobj.IsTopmost);
}

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

private void SetTopmostState(bool isTop)
{
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;

if (isTop)
{
SetWindowPos(hwnd, HWND_TOPMOST, rect.Left, rect.Top, (int)Width, (int)Height, TOPMOST_FLAGS);
}
else
{
// 重新激活Topmost,需要bottom->top->notop
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;
}

[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 */

//很重要,窗口切换等需要将popup显示层级重新刷新
const UInt32 TOPMOST_FLAGS =
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
}

以上是关于Popup 解决StayOpen=true时,置顶的问题的主要内容,如果未能解决你的问题,请参考以下文章

解决 Popup 位置不随窗口移动更新的问题

解决 Popup 位置不随窗口移动更新的问题

Android 如何在进入有scrollView的页面时滑动条置顶

自定义WPF Popup控件

WPF中的Popup控件,遇到个问题,求助

关于wpf中popup跟随鼠标移动显示