Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>The visual studio team has some good information on lessons they learned when making VS in WPF. One of the issues they ran into was related to Focus management. As a result, WPF 4 has some new features to help out.</p> <p>Here's the info on the issue that sounds like your situation:</p> <p><a href="http://blogs.msdn.com/b/visualstudio/archive/2010/03/09/wpf-in-visual-studio-2010-part-3-focus-and-activation.aspx" rel="noreferrer">http://blogs.msdn.com/b/visualstudio/archive/2010/03/09/wpf-in-visual-studio-2010-part-3-focus-and-activation.aspx</a></p> <p>Their discussion of the new "HwndSource.DefaultAcquireHwndFocusInMenuMode" property sounds very similar to what you're running into.</p> <p><strong>EDIT</strong></p> <p>After further investigation, it looks like Visual Studio might be hooking the windows message loop and returning specific values to make the floating windows work. </p> <p>I'm not a win32 programmer, but it seems that when a user clicks a menu in an inactive window, windows sends the <a href="http://msdn.microsoft.com/en-us/library/ms645612%28v=vs.85%29.aspx" rel="noreferrer">WM_MOUSEACTIVATE</a> message to it before processing the mouse down event. This lets the main window determine whether it should be activated. </p> <p>In my unmodified WPF test app, the inactive window returns <a href="http://msdn.microsoft.com/en-us/library/ms645612%28v=vs.85%29.aspx" rel="noreferrer">MA_ACTIVATE</a>. However, VS returns <a href="http://msdn.microsoft.com/en-us/library/ms645612%28v=vs.85%29.aspx" rel="noreferrer">MA_NOACTIVATE</a>. The docs indicate that this tells windows NOT to activate the main window prior to handling further input. I'm guessing that visual studio hooks the windows message loop and returns <a href="http://msdn.microsoft.com/en-us/library/ms645612%28v=vs.85%29.aspx" rel="noreferrer">MA_NOACTIVATE</a> when the user clicks on the menus / toolbars.</p> <p>I was able to make this work in a simple, two window WPF app by adding this code to the top level window.</p> <pre><code> protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); var hook = new HwndSourceHook(this.FilterMessage); var source2 = HwndSource.FromVisual(this) as HwndSource; source2.AddHook(hook); } private IntPtr FilterMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { const int WM_MOUSEACTIVATE = 0x0021; const int MA_NOACTIVATE = 3; switch (msg) { case WM_MOUSEACTIVATE: handled = true; return new IntPtr(MA_NOACTIVATE); } return IntPtr.Zero; } </code></pre> <p>In your case, you'd probably need to add more logic that would check what the user clicked on and decide based on that whether to intercept the message and return MA_NOACTIVATE.</p> <p><strong>EDIT 2</strong></p> <p>I've attached a <a href="http://blog.alner.net/downloads/floatingWindowTest.zip" rel="noreferrer">sample WPF application</a> that shows how to do this with a simple WPF application. This should work pretty much the same with floating windows from a docking toolkit, but I haven't tested that specific scenario.</p> <p>The sample is available at: <a href="http://blog.alner.net/downloads/floatingWindowTest.zip" rel="noreferrer">http://blog.alner.net/downloads/floatingWindowTest.zip</a> </p> <p>The sample has code comments to explain how it works. To see it in action, run the sample, click the "open another window" button. This should put focus in the textbox of the new window. Now, click the edit menu of the main window and use the commands like "select all". These should operate on the other window without bringing the "main window" to the foreground.</p> <p>You can also click on the "exit" menu item to see that it can still route commands to the main window if needed.</p> <p>Key Points (Activation / Focus):</p> <ol> <li>Use the HwndSource.DefaultAcquireHwndFocusInMenuMode to get the menus to work stop grabbing focus.</li> <li>Hook the message loop and return "MA_NOACTIVATE" when the user clicks the menu.</li> <li>Add an event handler to the menu's PreviewGotKeyboardFocus and set e.Handled to true so that the menu wont' attempt to grab focus.</li> </ol> <p>Key Points (Commands):</p> <ol> <li>Hook the main window's "CommandManager.PreviewCanExecute" and "CommandManager.PreviewExecuted" events.</li> <li>In these events, detect whether the app has an "other window" that's supposed to be the target of events.</li> <li>Manually invoke the original command against the "other window".</li> </ol> <p>Hope it works for you. If not, let me know.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload