Disable WPF Window Focus
Asked Answered
K

5

25

I have a WPF Window that shows up only when you hold down the tab key via Visibility.Hidden and Visibility.Visible. However, holding the key down shifts the focus from the active application to the WPF Window. Can I disable this behavior? Going even further: is it possible to completely prevent the window from getting focus even when a control is clicked, but still registering the click action of the control?

Kidwell answered 25/9, 2012 at 22:15 Comment(3)
Possible duplicate of Show a Form without stealing focus?Adieu
@Adieu This is different as the other question is asking how to show without taking focus, but is vague on whether or not user interaction is allowed. The answers also only solve the portion of no activation, but not it's not clear if user interaction is allowed (top selected answer does not).Kidwell
@Adieu But this question quite prominently concerns WPF, and your link is for a WinForms question. Despite both GUIs allowing the recourse of falling back to Win32, in my experience, the focus situation is an especially elaborate and complex feature area in WPF compared to the former, meaning (for "focus" issues specifically) what works for Win32/WinForms may not be workable for WPF.Dollop
K
25

Found the answer elsewhere:

protected override void OnSourceInitialized(EventArgs e)
{
    base.OnSourceInitialized(e);

    //Set the window style to noactivate.
    var helper = new WindowInteropHelper(this);
    SetWindowLong(helper.Handle, GWL_EXSTYLE,
        GetWindowLong(helper.Handle, GWL_EXSTYLE) | WS_EX_NOACTIVATE);
}   

private const int GWL_EXSTYLE = -20;
private const int WS_EX_NOACTIVATE = 0x08000000;

[DllImport("user32.dll")]
public static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

[DllImport("user32.dll")]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
Kidwell answered 27/9, 2012 at 19:0 Comment(3)
This needs to happen in the Loaded event, which occurs before the Activated event. If you do it in OnActivated, the window is already activated and its too late... it only prevents focus from that point out.Flowery
Better to use SourceInitializedAshliashlie
It's better to use SetWindowLongPtr and GetWindowLongPtr. See definitions on the pinvoke.net web site.Curkell
F
15

Since .NET 3.5 SP1 WPF forms have a ShowActivated property. Set this to false and the form thus marked won't steal no focus no more.

Fairfax answered 25/9, 2012 at 23:15 Comment(1)
I have tried this already. It just causes my program to crash.Kidwell
T
7

You can prevent a WPF Window from activating on mouse click by adding a custom WndProc and handling WM_MOUSEACTIVATE:

protected override void OnSourceInitialized(EventArgs e)
{
    base.OnSourceInitialized(e);
    var source = PresentationSource.FromVisual(this) as HwndSource;
    source.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    if (msg == WM_MOUSEACTIVATE)
    {
        handled = true;
        return new IntPtr(MA_NOACTIVATE);
    }
    else return IntPtr.Zero;
}
private const int WM_MOUSEACTIVATE = 0x0021;
private const int MA_NOACTIVATE = 0x0003;

References:

Trucker answered 11/12, 2015 at 13:7 Comment(2)
I never get a message WM_MOUSEACTIVATEMetamorphism
Wow! I've been looking for a solution to this problem for 2 days and it's the only one that did it for me! Thank you so much for this fantastic piece of code and for making me learn :)Kendrakendrah
D
5

Prevent certain top-level windows from getting activated in WPF:

I tried the Win32 solution given here but it didn't work for me. While it does seem to prevent window "activation," the Focus is left in limbo afterwards, not restored to another eligible window in your application. Instead, the following worked for me:

First, make sure that all the non-primary windows have their Owner property set to the main Window. I do this in the constructor of the sub-window, in which case one must take some steps (not discussed here) to make sure that the main Window is loaded first.

public MySubWindow()
{
    if ((base.Owner = Application.Current.MainWindow) == null)
        throw new Exception();

    InitializeComponent();
}

Setting the Owner property should also ensure that the sub windows stay on top of the main window. For the sub window(s), set the following properties as indicated (XAML or code):

ShowActivated="False"
Focusable="False"
ShowInTaskbar="False"
IsEnabled="False"
FocusManager.IsFocusScope="False"

Finally, add a handler for OnActivated to the blocked windows. I don't call the base method since it fires the Activated event. (Note that you should not switch the activation away from the Visual Studio designer since it makes the window invisible).

protected override void OnActivated(EventArgs e)
{
    if (DesignerProperties.GetIsInDesignMode(this))
        return;

    base.Owner.Activate();
}
Dollop answered 18/5, 2015 at 4:25 Comment(1)
I really liked it. No C calls and even focuses the main window. This behavior is even better for the particular app. Constructors should not throw errors. base.Owner<- do not need to "base" simple Owner is sufficient.Orji
A
0

Maybe a PopupWindow instead of Window would be what you want? It has a property of Focusable which you can set to false (it might be false by default I think).

Asel answered 26/9, 2012 at 0:13 Comment(1)
You can see here: msdn.microsoft.com/en-us/library/system.windows.window.aspx that Window also has a Focusable property. I've tried setting everything to Focusable = false, but it still doesn't resolve my issue.Kidwell

© 2022 - 2024 — McMap. All rights reserved.