protected override void WndProc(ref Message m) { if (DesignMode) { base.WndProc(ref m); return; } switch ((Window.Msg)m.Msg) { case Window.Msg.WM_NCCALCSIZE: // Check WPARAM if (m.WParam != IntPtr.Zero) { // When TRUE, LPARAM Points to a NCCALCSIZE_PARAMS structure var nccsp = (WinApi.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(WinApi.NCCALCSIZE_PARAMS)); ApplyPreferedSize(_preferedSize, nccsp.rectProposed.Size); AdjustClientArea(ref nccsp.rectProposed); Marshal.StructureToPtr(nccsp, m.LParam, true); } else { // When FALSE, LPARAM Points to a RECT structure var clnRect = (WinApi.RECT)Marshal.PtrToStructure(m.LParam, typeof(WinApi.RECT)); ApplyPreferedSize(_preferedSize, clnRect.Size); AdjustClientArea(ref clnRect); Marshal.StructureToPtr(clnRect, m.LParam, true); } //Return Zero m.Result = IntPtr.Zero; break; case Window.Msg.WM_NCPAINT: PaintScrollBars(null); // we handled everything m.Result = IntPtr.Zero; break; case Window.Msg.WM_NCHITTEST: // we need to correctly handle this if we want the non client area events (WM_NC*) to fire properly! var point = PointToClient(new Point(m.LParam.ToInt32())); if (!ClientRectangle.Contains(point)) { m.Result = (IntPtr)WinApi.HitTest.HTBORDER; } else { base.WndProc(ref m); } break; case Window.Msg.WM_MOUSEWHEEL: if (HasScroll) { // delta negative when scrolling up var delta = (short)(m.WParam.ToInt64() >> 16); var mouseEvent1 = new MouseEventArgs(MouseButtons.None, 0, 0, 0, delta); if (HorizontalScroll.IsHovered) { HorizontalScroll.HandleScroll(null, mouseEvent1); } else { VerticalScroll.HandleScroll(null, mouseEvent1); } } else { // propagate the event base.WndProc(ref m); } break; case Window.Msg.WM_MOUSEMOVE: if (VerticalScroll.IsThumbPressed) { VerticalScroll.HandleMouseMove(null, null); } if (HorizontalScroll.IsThumbPressed) { HorizontalScroll.HandleMouseMove(null, null); } base.WndProc(ref m); break; case Window.Msg.WM_NCMOUSEMOVE: // track mouse leaving (otherwise the WM_NCMOUSELEAVE message would not fire) WinApi.TRACKMOUSEEVENT tme = new WinApi.TRACKMOUSEEVENT(); tme.cbSize = (uint)Marshal.SizeOf(tme); tme.dwFlags = (uint)(WinApi.TMEFlags.TME_LEAVE | WinApi.TMEFlags.TME_NONCLIENT); tme.hwndTrack = Handle; WinApi.TrackMouseEvent(tme); // PointToClient(new Point(m.LParam.ToInt32())); VerticalScroll.HandleMouseMove(null, null); HorizontalScroll.HandleMouseMove(null, null); base.WndProc(ref m); break; case Window.Msg.WM_NCLBUTTONDOWN: VerticalScroll.HandleMouseDown(null, null); HorizontalScroll.HandleMouseDown(null, null); Focus(); // here we forward to base button down because it has a internal focus mecanism that we want to exploit // if we don't do that, the mouse MOVE events are not fired outside the bounds of this control! m.Msg = (int)Window.Msg.WM_LBUTTONDOWN; base.WndProc(ref m); break; case Window.Msg.WM_NCLBUTTONUP: case Window.Msg.WM_LBUTTONUP: VerticalScroll.HandleMouseUp(null, null); HorizontalScroll.HandleMouseUp(null, null); // here we forward this message to base WM_LBUTTONUP to release the internal focus on this control m.Msg = (int)Window.Msg.WM_LBUTTONUP; base.WndProc(ref m); break; case Window.Msg.WM_NCMOUSELEAVE: VerticalScroll.HandleMouseLeave(null, null); HorizontalScroll.HandleMouseLeave(null, null); base.WndProc(ref m); break; default: base.WndProc(ref m); break; } }
protected virtual void MouseLeaveClientArea(EventArgs eventArgs) { VerticalScroll.HandleMouseLeave(null, null); HorizontalScroll.HandleMouseLeave(null, null); }