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,false);
// 用於踢掉其他的在上層的視窗
window.Topmost = true;
window.Topmost = false;
我測試了幾個原本沒有讓視窗放在上層的裝置,使用上面的程式碼可以設定,但是我不瞭解設定上面程式碼可能的坑是什麼
附帶 walterlv 的測試工具,可以用來拿到當前的 GetForegroundWindow 是哪個
另外少君小夥伴寫了一個有趣的庫,裡面封裝了很多 win32 的方法,請看 kkwpsv lsjutil