遵循MS准则,我的
WPF应用程序的App构造函数包含以下代码以实现正确的焦点行为:
HwndSource.DefaultAcquireHwndFocusInMenuMode = false; Keyboard.DefaultRestoreFocusMode = RestoreFocusMode.None;
如this article中所述,这些设置可防止焦点窃取.
但是,将DefaultRestoreFocusMode设置为None会产生不良副作用.当使用Alt Tab离开WPF应用程序然后返回它时,WPF应用程序不会获得焦点.但是,如果我没有将DefaultRestoreFocusMode设置为none,它会按预期获得焦点.有没有办法防止焦点窃取,但通过Alt Tab返回到WPF应用程序时仍然设置焦点?
-Craig
解决方法
我通过执行以下操作来阻止我的wpf窗口获得焦点,我仍然可以使用ALT-TAB或单击它的任务栏项来激活它.
在这里,您可以更改窗口上的窗口样式,使其无法激活.
var yourWindow = new YourWindowType(); //set the windowstyle to noactivate so the window doesn't get focus yourWindow.SourceInitialized += (s,e) => { var interopHelper = new WindowInteropHelper(yourWindow); int exStyle = User32.GetWindowLong(interopHelper.Handle,(int)WindowLongFlags.GWL_EXSTYLE); User32.SetWindowLong(interopHelper.Handle,(int)WindowLongFlags.GWL_EXSTYLE,exStyle | (int)WindowStylesEx.WS_EX_NOACTIVATE); //If you have trouble typing into your form's textBoxes then do this ElementHost.EnableModelessKeyboardInterop(yourWindow); };
这是我作为额外的预防措施添加的东西,而且如果它是无边界的,它可以让你拖动你的窗口:
private IntPtr WndProc(IntPtr hwnd,int msg,IntPtr wParam,IntPtr lParam,ref bool handled) { switch (msg) { //don't activate the window when you click on it. case WindowMessage.WM_MOUSEACTIVATE: handled = true; return (IntPtr)MouseActivate.MA_NOACTIVATE; //For Borderless Windows: occurs while dragging. it reports new position before it has been finalized. //otherwise you wont see the window moving while you're dragging it case WindowMessage.WM_MOVING: RECT rect = (RECT)Marshal.PtrToStructure(lParam,typeof(RECT)); User32.SetWindowPos(new WindowInteropHelper(this).Handle,Hwnd.HWND_TOPMOST,rect.Left,rect.Top,rect.Width,rect.Height,SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOSIZE); break; } return IntPtr.Zero; }
private void Window_Loaded(object sender,RoutedEventArgs e) { HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle); if (source == null) return; source.AddHook(WndProc); } private void Window_Closing(object sender,System.ComponentModel.CancelEventArgs e) { HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle); if (source == null) return; source.RemoveHook(WndProc); }
只是一个FYI ..即使你没有得到关注,这仍然有效:
private void WpfPillForm_MouseLeftButtonDown(object sender,MouseButtonEventArgs e) { this.DragMove(); }
这是Win32 API声明,因此您无需查找它们:
[StructLayout(LayoutKind.Sequential)] public struct WINDOWPOS { public IntPtr hwnd; public IntPtr hwndInsertAfter; public int x; public int y; public int cx; public int cy; public int flags; } [StructLayout(LayoutKind.Sequential)] struct RECT { public int left,top,right,bottom; } public static class MouseActivate { public const int MA_ACTIVATE = 1; public const int MA_ACTIVATEANDEAT = 2; public const int MA_NOACTIVATE = 3; public const int MA_NOACTIVATEANDEAT = 4; } public enum WindowLongFlags : int { GWL_EXSTYLE = -20,GWLP_HINSTANCE = -6,GWLP_HWNDPARENT = -8,GWL_ID = -12,GWL_STYLE = -16,GWL_USERDATA = -21,GWL_WNDPROC = -4,DWLP_USER = 0x8,DWLP_MSGRESULT = 0x0,DWLP_DLGPROC = 0x4 } public const int WM_MOVING = 0x0216; public const uint WS_EX_NOACTIVATE = 0x08000000,[DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetWindowPos(IntPtr hWnd,IntPtr hWndInsertAfter,int X,int Y,int cx,int cy,SetWindowPosFlags uFlags); [DllImport("user32.dll",CharSet = CharSet.Auto,SetLastError = true)] public static extern int SetWindowLong(IntPtr hWnd,int nIndex,int dwNewLong); [DllImport("user32.dll",SetLastError = true)] public static extern int GetWindowLong(IntPtr hwnd,int index);