As Marco Zhou has said in the msdn forum
():
Windows will only send WM_IME_SETCONTEXT message to the active window,
Popup by default is designed to be shown with WM_EX_NOACTIVE which
means that it doesn’t in active state when displaying, that’s why IME
could not work correctly in this regard, to workaround this issue, you
could try set the Popup as the active window using win32
SetActiveWindow() API.

/// <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));

So the workaround is use MyPopup instead of Popup:

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

public class MyPopup : Popup
{
    [DllImport(“user32.dll”)]
    static extern IntPtr SetActiveWindow(IntPtr hWnd);

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

    static MyPopup()
    {
        EventManager.RegisterClassHandler(
            typeof(MyPopup),
            Popup.PreviewGotKeyboardFocusEvent,
            new
KeyboardFocusChangedEventHandler(OnPreviewGotKeyboardFocus),
            true);
    }

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

    private static void OnPreviewGotKeyboardFocus(Object sender,
KeyboardFocusChangedEventArgs e)
    {
        var textBox = e.NewFocus as TextBoxBase;
        if (textBox != null)
        {
            var hwndSource = PresentationSource.FromVisual(textBox) as
HwndSource;
            if (hwndSource != null)
            {
                SetActiveWindow(hwndSource.Handle);
            }
        }
    }
}

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

官方消除方案

_alreadyLoaded = true;

选取的话本人建一个类代码如上,控件内local:MyPopup
等同于Popup,亲测好使,实用。

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

相关文章