2012-03-22 5 views
1

Я внедрил пользовательское окно chrome с помощью библиотеки интеграции оболочки WPF (http://archive.msdn.microsoft.com/WPFShell).Система Закрыть поверхности кнопок в пользовательском окне chrome, когда ResizeMode установлен в NoResize

Хром работает, пока я не установил ReSizeMode в NoResize. Затем, если наведите курсор на кнопку «Закрыть», я заметил, что базовая кнопка «Закрыть систему» ​​отображается под пользовательской кнопкой закрытия хрома. Custom Chrome Button partially hides System Close Button

Ожидаемое поведение заключается в том, что основная кнопка закрытия не должна отображаться. Если я переместлю окно или выберу другое окно на своем рабочем столе и вернусь к нему, я заметил, что кнопка закрытия системы снова скрыта. Таким образом, вероятно, по существу, когда (1) первый запуск приложения и (2), когда ResizeMode = NoResize.

Мое первое подозрение заключается в том, как мы обрабатываем WM.NCHITTEST в пользовательском Chrome. Если я изменю эту функцию, чтобы вернуть HTCLient, эта проблема будет решена. Тем не менее, я теряю способность перетаскивать, а также щелкнуть правой кнопкой мыши на панели надписей.

Вот код для обработчика сообщения WM.NCHITTEST из класса WindowsChromeWorker.

private IntPtr _HandleNCHitTest(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) { 
     IntPtr lRet = IntPtr.Zero; 
     handled = false; 

     // Give DWM a chance at this first. 
     if (Utility.IsOSVistaOrNewer && _chromeInfo.GlassFrameThickness != default(Thickness) && _isGlassEnabled) { 
      // If we're on Vista, give the DWM a chance to handle the message first. 
      handled = NativeMethods.DwmDefWindowProc(_hwnd, uMsg, wParam, lParam, out lRet); 
     } 


     // Handle letting the system know if we consider the mouse to be in our effective non-client area. 
     // If DWM already handled this by way of DwmDefWindowProc, then respect their call. 
     if (IntPtr.Zero == lRet) { 
      var mousePosScreen = new Point(Utility.GET_X_LPARAM(lParam), Utility.GET_Y_LPARAM(lParam)); 
      Rect windowPosition = _GetWindowRect(); 

      HT ht = _HitTestNca(
       DpiHelper.DeviceRectToLogical(windowPosition), 
       DpiHelper.DevicePixelsToLogical(mousePosScreen)); 

      // Don't blindly respect HTCAPTION. 
      // We want UIElements in the caption area to be actionable so run through a hittest first. 
      if (ht != HT.CLIENT) { 
       Point mousePosWindow = mousePosScreen; 
       mousePosWindow.Offset(-windowPosition.X, -windowPosition.Y); 
       mousePosWindow = DpiHelper.DevicePixelsToLogical(mousePosWindow); 
       IInputElement inputElement = _window.InputHitTest(mousePosWindow); 
       if (inputElement != null && WindowChrome.GetIsHitTestVisibleInChrome(inputElement)) { 
        ht = HT.CLIENT; 
       } 
      } 
      //handled = false; 
      handled = true; 
      lRet = new IntPtr((int)ht); 
     } 
     return lRet; 
    } 

    private static readonly HT[,] _HitTestBorders = new[,] 
    { 
     { HT.TOPLEFT, HT.TOP,  HT.TOPRIGHT }, 
     { HT.LEFT,  HT.CLIENT, HT.RIGHT  }, 
     { HT.BOTTOMLEFT, HT.BOTTOM, HT.BOTTOMRIGHT }, 
    }; 

    private HT _HitTestNca(Rect windowPosition, Point mousePosition) { 
     // Determine if hit test is for resizing, default middle (1,1). 
     int uRow = 1; 
     int uCol = 1; 
     bool onResizeBorder = false; 

     //if (_window.ResizeMode == ResizeMode.NoResize) 
      // _chromeInfo.ResizeBorderThickness = new Thickness(0); 

     // Determine if the point is at the top or bottom of the window. 
     if (mousePosition.Y >= windowPosition.Top && mousePosition.Y < windowPosition.Top + _chromeInfo.ResizeBorderThickness.Top + _chromeInfo.CaptionHeight) { 
      onResizeBorder = (mousePosition.Y < (windowPosition.Top + _chromeInfo.ResizeBorderThickness.Top)); 
      uRow = 0; // top (caption or resize border) 
     } else if (mousePosition.Y < windowPosition.Bottom && mousePosition.Y >= windowPosition.Bottom - (int)_chromeInfo.ResizeBorderThickness.Bottom) { 
      uRow = 2; // bottom 
     } 

     // Determine if the point is at the left or right of the window. 
     if (mousePosition.X >= windowPosition.Left && mousePosition.X < windowPosition.Left + (int)_chromeInfo.ResizeBorderThickness.Left) { 
      uCol = 0; // left side 
     } else if (mousePosition.X < windowPosition.Right && mousePosition.X >= windowPosition.Right - _chromeInfo.ResizeBorderThickness.Right) { 
      uCol = 2; // right side 
     } 

     // If the cursor is in one of the top edges by the caption bar, but below the top resize border, 
     // then resize left-right rather than diagonally. 
     if (uRow == 0 && uCol != 1 && !onResizeBorder) { 
      uRow = 1; 
     } 

     HT ht = _HitTestBorders[uRow, uCol]; 

     if (ht == HT.TOP && !onResizeBorder) { 
      ht = HT.CAPTION; 
     } 

     return ht; 
    } 

Любые идеи, как исправить это?

Большое спасибо, Арджун

ответ

2

Все rite..I было понять эту проблему вне.

Прежде всего, мои первоначальные подозрения были неправильными. Обработка сообщения WM.NCHITTEST was not. Это был вопрос Window Styles.

Лучшим решением было скрыть кнопку «Закрыть систему» ​​и позволить кнопке Chrome Close выполнить свою работу. Но решение, которое вы найдете в сети, переключилось на флаг SYSMENU в стилях Window http://winsharp93.wordpress.com/2009/07/21/wpf-hide-the-window-buttons-minimize-restore-and-close-and-the-icon-of-a-window/, но в моем случае это не сработало.

Кнопка «Закрыть» скрыта, но несмотря на то, что параметр ResizeMode установлен на NoResize, я заметил, что оба параметра «Изменение размера курсора» и «Изменение размера» {Max \ Min \ Restore} были включены.

Через несколько часов проб и ошибок, я придумал этот кусок кода:

//This property descriptor is used to hook-onto the resizemode change notification 

     private void Window_Loaded(object sender, System.Windows.RoutedEventArgs e) 
     { 
     // When the default handling of ResizeMode = NoResize causes problems - this is why custom handling is required. 
    System.ComponentModel.DependencyPropertyDescriptor _resizeModePropertyDescriptor; 

    _resizeModePropertyDescriptor = System.ComponentModel.DependencyPropertyDescriptor.FromProperty(Window.ResizeModeProperty, 
      typeof(Window)); 
     _resizeModePropertyDescriptor.AddValueChanged(this._window, new EventHandler(this._Window_ResizeModePropertyChanged)); 
     } 

    /// <summary> 
    /// This property change handler only reacts when the ReSizeMode is set to NoResize. 
    /// In the default window style when Resize = NoResize, causes the underlying system close button to show up under the Chrome Close Button. 
    /// This is a fix to handle that problem. [ Refer to defect #5134 for further details. 
    /// </summary> 
    /// <param name="sender">ChromeWorker object</param> 
    /// <param name="e">Event Args - Not really used</param> 
    private void _Window_ResizeModePropertyChanged(object sender, EventArgs e) 
    { 
     if (_window.ResizeMode == ResizeMode.NoResize) 
     { 
      //Got these styles merely by trial and error. 
      _ModifyStyle(
       WS.SYSMENU | WS.DLGFRAME | WS.BORDER | WS.CLIPCHILDREN | WS.CLIPSIBLINGS, //Styles to Remove 
       WS.POPUPWINDOW);               //Style to Add 
     } 
    } 

    /// <summary>Add and remove a native WindowStyle from the HWND.</summary> 
    /// <param name="removeStyle">The styles to be removed. These can be bitwise combined.</param> 
    /// <param name="addStyle">The styles to be added. These can be bitwise combined.</param> 
    /// <returns>Whether the styles of the HWND were modified as a result of this call.</returns> 
    private bool _ModifyStyle(WS removeStyle, WS addStyle) { 
     Assert.IsNotDefault(_hwnd); 
     var dwStyle = (WS)NativeMethods.GetWindowLongPtr(_hwnd, GWL.STYLE).ToInt32(); 
     var dwNewStyle = (dwStyle & ~removeStyle) | addStyle; 
     if (dwStyle == dwNewStyle) { 
      return false; 
     } 

     NativeMethods.SetWindowLongPtr(_hwnd, GWL.STYLE, new IntPtr((int)dwNewStyle)); 
     return true; 
    } 

Вы также можете использовать событие SourceInitialized для wireup, но я действительно нету проверял это. Thats it! Это захватывает напряженную неделю исследования оконных хромов!

Я должен признать, что я немного заинтригован - WOKING на WPF так долго не сделал мне понять, что есть целый мир win32 там, который является гораздо более мощным

(и разочарование, как хорошо!)