#wpf
#wpf
Вопрос:
Следуя рекомендациям MS, конструктор приложений моего приложения WPF включает следующий код для правильного поведения фокуса:
HwndSource.DefaultAcquireHwndFocusInMenuMode = false;
Keyboard.DefaultRestoreFocusMode = RestoreFocusMode.None;
Как объясняется в этой статье, эти настройки предотвращают кражу фокуса.
Однако установка DefaultRestoreFocusMode в значение None имеет плохой побочный эффект. При использовании Alt Tab для выхода из приложения WPF, а затем возврата к нему, приложение WPF не получает фокус. Однако, если я не установлю для DefaultRestoreFocusMode значение none, он получит фокус, как и ожидалось. Есть ли способ предотвратить кражу фокуса, но при этом сохранить фокус при возврате в приложение WPF с помощью Alt Tab?
-Крейг
Комментарии:
1. Я не могу воспроизвести поведение, вероятно, я упускаю важную деталь. Я предполагаю, что приложение. Активированное событие бесполезно?
Ответ №1:
Я предотвращаю фокусировку моего окна 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;
}
Они добавляют перехват, так что WndProc фактически вызывается в WPF:
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);
}
Просто к вашему сведению .. это все еще работает, даже если вы не получаете фокус:
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", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowLong(IntPtr hwnd, int index);