WPF 讓窗口激活作為前台最上層窗口的方法


在 WPF 中,如果想要使用代碼控制,讓某個窗口作為當前用戶的輸入的邏輯焦點的窗口,也就是在當前用戶活動的窗口的最上層窗口,默認使用 Activate 方法,通過這個方法在大部分設備都可以做到激活窗口

但是在一些特殊的設備上,使用下面代碼調起窗口只是在任務欄閃爍圖標,而沒有讓窗口放在最上層

window.Show();
window.Activate();

在大部分設備上,通過 Show 和 Activate 組合可以讓窗口作為當前用戶活動的,即使窗口之前是最小化或隱藏,都可以通過 Show 的方法顯示

但是某些設備窗口被蓋在其他的窗口的下面,此時的窗口的 window.IsActive 還是 true 但是調用 Activate 不會讓窗口放在上層

我在網上看到好多小伙伴調用了 SetForegroundWindow 方法,其實現在 WPF 是開源的,可以看到 Window 的 Activate 方法是這樣寫

        public bool Activate()
        {
            // this call ends up throwing an exception if Activate
            // is not allowed
            VerifyApiSupported();
            VerifyContextAndObjectState();
            VerifyHwndCreateShowState();

            // Adding check for IsCompositionTargetInvalid
            if (IsSourceWindowNull || IsCompositionTargetInvalid)
            {
                return false;
            }

            return UnsafeNativeMethods.SetForegroundWindow(new HandleRef(null, CriticalHandle));
        }

源代碼請看 github

也就是調用 SetForegroundWindow 和調用 Activate 方法是差不多的,如果調用 Activate 應該調用 SetForegroundWindow 也差不多

通過大佬的 SetForegroundWindow的正確用法 - 子塢 - 博客園 可以了解到,需要按照以下步驟

    1.得到窗口句柄FindWindow 
    2.切換鍵盤輸入焦點AttachThreadInput 
    3.顯示窗口ShowWindow(有些窗口被最小化/隱藏了) 
    4.更改窗口的Zorder,SetWindowPos使之最上,為了不影響后續窗口的Zorder,改完之后,再還原 
    5.最后SetForegroundWindow 

在 WPF 中對應的更改窗口的順序使用的是 Topmost 屬性,同時設置順序需要做一定小的更改

在 WPF 中通過 c# - Bring a window to the front in WPF - Stack Overflow 可以了解到如何用 AttachThreadInput 方法

整個代碼請看下面,具體的 win32 方法我就沒有寫出來了,請小伙伴自己添加

        private static void SetWindowToForegroundWithAttachThreadInput(Window window)
        {
            var interopHelper = new WindowInteropHelper(window);
            var thisWindowThreadId = Win32.User32.GetWindowThreadProcessId(interopHelper.Handle, IntPtr.Zero);
            var currentForegroundWindow = Win32.User32.GetForegroundWindow();
            var currentForegroundWindowThreadId = Win32.User32.GetWindowThreadProcessId(currentForegroundWindow, IntPtr.Zero);

            // [c# - Bring a window to the front in WPF - Stack Overflow](https://stackoverflow.com/questions/257587/bring-a-window-to-the-front-in-wpf )
            // [SetForegroundWindow的正確用法 - 子塢 - 博客園](https://www.cnblogs.com/ziwuge/archive/2012/01/06/2315342.html )
            /*
                 1.得到窗口句柄FindWindow 
                2.切換鍵盤輸入焦點AttachThreadInput 
                3.顯示窗口ShowWindow(有些窗口被最小化/隱藏了) 
                4.更改窗口的Zorder,SetWindowPos使之最上,為了不影響后續窗口的Zorder,改完之后,再還原 
                5.最后SetForegroundWindow 
             */
            Win32.User32.AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, true);

            window.Show();
            window.Activate();
            // 去掉和其他線程的輸入鏈接
            Win32.User32.AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, false);

            // 用於踢掉其他的在上層的窗口
            window.Topmost = true;
            window.Topmost = false;

我測試了幾個原本沒有讓窗口放在上層的設備,使用上面的代碼可以設置,但是我不了解設置上面代碼可能的坑是什么

附帶 walterlv 的測試工具,可以用來拿到當前的 GetForegroundWindow 是哪個

walterlv 的工具

另外少君小伙伴寫了一個有趣的庫,里面封裝了很多 win32 的方法,請看 kkwpsv lsjutil


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM