可停靠的Windows.浮动窗口和MainWindow菜单集成 [英] Dockable Windows. Floating Window and MainWindow Menu Integration

查看:159
本文介绍了可停靠的Windows.浮动窗口和MainWindow菜单集成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Visual Studio 2010中,可停靠Windows似乎在每种情况下都可以正常工作.
如果浮动"文档处于活动状态并且选择了某些菜单(例如,编辑"->粘贴"),则浮动"文档仍具有焦点",并且将对该浮动"窗口执行命令.另外,请注意在用户界面中如何清晰可见.即使选择了团队菜单,MainWindow.xaml仍然处于活动状态,而Visual Studio中的主窗口处于非活动状态.

In Visual Studio 2010, Dockable Windows seem to work like expected in every situation.
If a "Floating" document is active and some menu is selected (e.g Edit -> Paste), then the "Floating" document still has Focus and the command will be executed against that "Floating" window. Also, notice how this is clearly visible in the UI. MainWindow.xaml is still active and the Main window in Visual Studio is inactive even though the Team-menu is selected.

我一直在尝试使用许多不同的第三方对接组件来获得相同的行为,但是它们都具有相同的问题:一旦选择菜单,MainWindow就被聚焦了,而我的浮动窗口不再具有焦点了.有谁知道在Visual Studio中获得相同行为的方法吗?

I've been trying to get the same behavior using alot of different 3rd-party docking components but they all have the same problem: once I select the menu, the MainWindow is focused and my floating window does not have focus anymore. Does anyone know of a way to get the same behavior here as in Visual Studio?

此刻,我正在使用 Infragistics xamDockManager 和可以使用以下示例代码重现该问题.

At the moment I'm using Infragistics xamDockManager and the problem can be reproduced with the following sample code.

  • 右键单击标题1",然后选择浮动"
  • 点击文件"菜单
  • 注意MainWindow如何获得焦点.

xmlns:igDock ="http://infragistics.com/DockManager"

xmlns:igDock="http://infragistics.com/DockManager"

<DockPanel LastChildFill="True">
    <Menu DockPanel.Dock="Top">
        <MenuItem Header="_File">
            <MenuItem Header="_New"/>
        </MenuItem>
    </Menu>
    <Grid>
        <igDock:XamDockManager x:Name="dockManager" Theme="Aero">
            <igDock:DocumentContentHost>
                <igDock:SplitPane>
                    <igDock:TabGroupPane>
                        <igDock:ContentPane Header="Header 1">
                            <TextBox Text="Some Text"/>
                        </igDock:ContentPane>
                        <igDock:ContentPane Header="Header 2">
                            <TextBox Text="Some Other Text"/>
                        </igDock:ContentPane>
                    </igDock:TabGroupPane>
                </igDock:SplitPane>
            </igDock:DocumentContentHost>
        </igDock:XamDockManager>
    </Grid>
</DockPanel>

推荐答案

在WPF中制作VS时,Visual Studio团队掌握了一些很好的信息.他们遇到的问题之一与Focus管理有关.因此,WPF 4具有一些新功能可以帮助您.

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.

以下是关于您所处情况的信息:

Here's the info on the issue that sounds like your situation:

他们对新的"HwndSource.DefaultAcquireHwndFocusInMenuMode"属性的讨论听起来与您所遇到的非常相似.

Their discussion of the new "HwndSource.DefaultAcquireHwndFocusInMenuMode" property sounds very similar to what you're running into.

编辑

经过进一步调查,看起来Visual Studio可能正在钩住Windows消息循环并返回特定值以使浮动窗口正常工作.

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.

我不是Win32程序员,但似乎当用户单击非活动窗口中的菜单时,Windows会发送

I'm not a win32 programmer, but it seems that when a user clicks a menu in an inactive window, windows sends the WM_MOUSEACTIVATE message to it before processing the mouse down event. This lets the main window determine whether it should be activated.

在我未修改的WPF测试应用程序中,非活动窗口返回 MA_NOACTIVATE .文档指示这告诉窗口在处理进一步的输入之前不要激活主窗口.我猜想Visual Studio会钩住Windows消息循环并返回

In my unmodified WPF test app, the inactive window returns MA_ACTIVATE. However, VS returns MA_NOACTIVATE. 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 MA_NOACTIVATE when the user clicks on the menus / toolbars.

通过将代码添加到顶层窗口中,我能够在一个简单的两个窗口WPF应用程序中完成这项工作.

I was able to make this work in a simple, two window WPF app by adding this code to the top level window.

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

在您的情况下,您可能需要添加更多逻辑来检查用户单击的内容,然后根据该逻辑决定是否拦截消息并返回MA_NOACTIVATE.

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.

编辑2

我附上了示例WPF应用程序,其中显示了如何使用简单的WPF应用程序.对于停靠工具箱中的浮动窗口,此方法应该几乎相同,但是我尚未测试该特定方案.

I've attached a sample WPF application 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.

可从以下位置获得该示例: http://blog.alner.net/downloads/floatingWindowTest. zip

The sample is available at: http://blog.alner.net/downloads/floatingWindowTest.zip

该示例具有代码注释,以解释其工作方式.要查看它的运行效果,请运行示例,单击打开另一个窗口"按钮.这应该将焦点放在新窗口的文本框中.现在,单击主窗口的编辑菜单,然后使用全选"之类的命令.这些应在其他窗口上运行,而不必将主窗口"置于前台.

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.

您还可以单击退出"菜单项,查看它是否仍可以根据需要将命令路由到主窗口.

You can also click on the "exit" menu item to see that it can still route commands to the main window if needed.

关键点(激活/重点):

Key Points (Activation / Focus):

  1. 使用HwndSource.DefaultAcquireHwndFocusInMenuMode来使菜单停止起作用.
  2. 钩住消息循环并在用户单击菜单时返回"MA_NOACTIVATE".
  3. 在菜单的PreviewGotKeyboardFocus中添加一个事件处理程序,并将e.Handled设置为true,以便菜单不会试图抓住焦点.

要点(命令):

  1. 钩住主窗口的"CommandManager.PreviewCanExecute"和"CommandManager.PreviewExecuted"事件.
  2. 在这些事件中,检测应用程序是否具有应作为事件目标的其他窗口".
  3. 在其他窗口"上手动调用原始命令.

希望它对您有用.如果没有,让我知道.

Hope it works for you. If not, let me know.

这篇关于可停靠的Windows.浮动窗口和MainWindow菜单集成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆