Dockable Windows. Floating Window and MainWindow Menu Integration

前端 未结 5 463
闹比i
闹比i 2020-12-29 12:58

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)

5条回答
  •  感动是毒
    2020-12-29 13:49

    I used the great answer from NathanAW and created a ResourceDictionary containing a Style for Window (which should be used by the MainWindow), contained the key pieces to solve this problem.

    Update: Added support for ToolBar as well as Menu

    It includes hit testing specifically for the MainMenu or ToolBar to decide if focusing should be allowed.

    The reason I've used a ResourceDictionary for this is for reusability since we will be using this in many projects. Also, the code behind for the MainWindow can stay clean.

    MainWindow can use this style with

    
        
            
                
                    
                
            
        
        
            
        
        
    
    

    NoFocusMenuWindowDictionary.xaml

    
        
        
        
    
    

    NoFocusMenuWindowDictionary.xaml.cs

    namespace MainWindowVS2010Mode
    {
        public partial class NoFocusMenuWindowDictionary
        {
            #region Declaration
    
            private static Window _mainWindow;
            private static bool _mainMenuOrToolBarClicked;
    
            #endregion // Declaration
    
            void MainWindow_Loaded(object sender, RoutedEventArgs e)
            {
                _mainWindow = sender as Window;
                HwndSource.DefaultAcquireHwndFocusInMenuMode = true;
                Keyboard.DefaultRestoreFocusMode = RestoreFocusMode.None;
                HwndSource hwndSource = HwndSource.FromVisual(_mainWindow) as HwndSource;
                hwndSource.AddHook(FilterMessage);
            }
    
            private static 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:
    
                        if (ClickedMainMenuOrToolBarItem())
                        {
                            handled = true;
                            return new IntPtr(MA_NOACTIVATE);
                        }
                        break;
                }
                return IntPtr.Zero;
            }
    
            #region Hit Testing
    
            private static bool ClickedMainMenuOrToolBarItem()
            {
                _mainMenuOrToolBarClicked = false;
                Point clickedPoint = Mouse.GetPosition(_mainWindow);
                VisualTreeHelper.HitTest(_mainWindow,
                                         null,
                                         new HitTestResultCallback(HitTestCallback),
                                         new PointHitTestParameters(clickedPoint));
                return _mainMenuOrToolBarClicked;
            }
    
            private static HitTestResultBehavior HitTestCallback(HitTestResult result)
            {
                DependencyObject visualHit = result.VisualHit;
                Menu parentMenu = GetVisualParent(visualHit);
                if (parentMenu != null && parentMenu.IsMainMenu == true)
                {
                    _mainMenuOrToolBarClicked = true;
                    return HitTestResultBehavior.Stop;
                }
                ToolBar parentToolBar = GetVisualParent(visualHit);
                if (parentToolBar != null)
                {
                    _mainMenuOrToolBarClicked = true;
                    return HitTestResultBehavior.Stop;
                }
                return HitTestResultBehavior.Continue;
            }
    
            public static T GetVisualParent(object childObject) where T : Visual
            {
                DependencyObject child = childObject as DependencyObject;
                while ((child != null) && !(child is T))
                {
                    child = VisualTreeHelper.GetParent(child);
                }
                return child as T;
            }
            #endregion // Hit Testing
    
            #region Menu
    
            private void Menu_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
            {
                Menu menu = sender as Menu;
                if (menu.IsMainMenu == true)
                {
                    e.Handled = true;
                }
            }
    
            #endregion // Menu
    
            #region ToolBar
    
            private void ToolBar_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
            {
                e.Handled = true;
            }
    
            #endregion // ToolBar
        }
    }
    

提交回复
热议问题