2011-10-01 7 views
7

Siguiendo las directrices MS, App el constructor de mi aplicación WPF incluye el siguiente código para un comportamiento adecuado enfoque:¿Cómo puedo evitar el robo de foco, pero aun así obtener el foco cuando regrese a mi aplicación usando Alt + Tab?

HwndSource.DefaultAcquireHwndFocusInMenuMode = false; 
Keyboard.DefaultRestoreFocusMode = RestoreFocusMode.None; 

Como se explica en this article, estos ajustes prevenir el robo de enfoque.

Sin embargo, establecer DefaultRestoreFocusMode en None tiene un mal efecto secundario. Al usar Alt + Tab para dejar una aplicación WPF y luego volver a ella, la aplicación WPF no obtiene el foco. Sin embargo, si no configuro DefaultRestoreFocusMode en none, obtiene el foco como se esperaba. ¿Hay alguna manera de evitar el robo de foco, pero aún así se ha establecido el foco al regresar a una aplicación WPF mediante Alt + Tab?

-Craig

+0

No soy capaz de replicar el comportamiento, probablemente me falta un detalle importante. Supongo que el evento Application.Activated no es útil. – ianschol

Respuesta

2

puedo evitar que mi ventana WPF de conseguir el enfoque al hacer el siguiente y todavía puede activarlo mediante el uso de ALT-TAB o hacer clic en su barra de tareas elemento.

Aquí cambia los estilos de ventana en su ventana para que no se active.

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

Esto es algo que añade como una precaución adicional, además de que le permite arrastrar la ventana en torno a si es sin fronteras:

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

estos añadir un gancho para que WndProc se llama en realidad en 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); 
} 

Sólo una intensa .. esto sigue funcionando a pesar de que usted no recibe el foco:

private void WpfPillForm_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
    { 
     this.DragMove(); 
    } 

He aquí las declaraciones de API Win32 por lo que no tiene que mirar hacia arriba:

[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); 
Cuestiones relacionadas