CefSharp中的可拖动无边框窗口

我想在一些HTML元素上使用拖动逻辑实现无边框窗口。 我找到了一些有用的例子(比如Chrome的无框窗口 ),这就是我尝试过的:

.title-area { -webkit-app-region: drag; } 
A draggable area

然后,在C#代码中我实现了IDragHandler类:

 internal class PromtDragHandler : IDragHandler { bool IDragHandler.OnDragEnter(IWebBrowser browserControl, IBrowser browser, IDragData dragData, DragOperationsMask mask) { return false; } void IDragHandler.OnDraggableRegionsChanged(IWebBrowser browserControl, IBrowser browser, IList regions) { } } 

方法OnDraggableRegionsChanged在开始时触发一次,OnDragEnter在我拖动元素“title-area”的某些文本时触发。 但我不知道接下来要做什么让我的窗户移动?

UPDATE。 如评论中所述, CefTestApp支持此拖动function。 在源代码中,我们有从DragHandler调用的方法OnSetDraggableRegions:

 void RootWindowWin::OnSetDraggableRegions( const std::vector& regions) { REQUIRE_MAIN_THREAD(); // Reset draggable region. ::SetRectRgn(draggable_region_, 0, 0, 0, 0); // Determine new draggable region. std::vector::const_iterator it = regions.begin(); for (;it != regions.end(); ++it) { HRGN region = ::CreateRectRgn( it->bounds.x, it->bounds.y, it->bounds.x + it->bounds.width, it->bounds.y + it->bounds.height); ::CombineRgn( draggable_region_, draggable_region_, region, it->draggable ? RGN_OR : RGN_DIFF); ::DeleteObject(region); } // Subclass child window procedures in order to do hit-testing. // This will be a no-op, if it is already subclassed. if (hwnd_) { WNDENUMPROC proc = !regions.empty() ? SubclassWindowsProc : UnSubclassWindowsProc; ::EnumChildWindows( hwnd_, proc, reinterpret_cast(draggable_region_)); } } 

我仍然不太了解,关于可拖动区域(在开始时仅触发一次)的确切信息如何有助于移动窗口? 有人可以解释我这个逻辑或提供C#等效的这段代码吗?

UPDATE2。 我做的。 这是我添加到表单代码中的内容:

 IntPtr DragableRegionNative = Native.CreateRectRgn(0, 0, 0, 0); void RegionsChangedCallback(DraggableRegion[] Regions) { Native.SetRectRgn(DragableRegionNative, 0, 0, 0, 0); if (Regions == null) return; foreach (var Region in Regions) { var RegionNative = Native.CreateRectRgn( Region.X, Region.Y, Region.X + Region.Width, Region.Y + Region.Height); Native.CombineRgn(DragableRegionNative, DragableRegionNative, RegionNative, Region.Draggable ? (int)Native.CombineRgnStyles.RGN_OR : (int)Native.CombineRgnStyles.RGN_DIFF); Native.DeleteObject(RegionNative); } } Point dragOffset = new Point(); protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); if (e.Button == MouseButtons.Left) { dragOffset = this.PointToScreen(e.Location); dragOffset.X -= Location.X; dragOffset.Y -= Location.Y; } } protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if (e.Button == MouseButtons.Left) { Point newLocation = this.PointToScreen(e.Location); newLocation.X -= dragOffset.X; newLocation.Y -= dragOffset.Y; Location = newLocation; } } void chromewb_IsBrowserInitializedChanged(object sender, IsBrowserInitializedChangedEventArgs e) { if (chromewb.IsBrowserInitialized) { ChromeWidgetMessageInterceptor.SetupLoop(chromewb, (m) => { if (m.Msg == (int)Native.WM.WM_LBUTTONDOWN) { var point = Native.ParsePoint(m.LParam.ToInt32()); if (Native.PtInRegion(DragableRegionNative, point.X, point.Y)) this.InvokeEx(() => Native.PostMessage(this.Handle, (uint)m.Msg, m.WParam, m.LParam)); } }); } } 

如您所见,从chrome浏览器拦截WM_LBUTTONDOWN事件就足够了,然后检查鼠标点是否属于标题区域,如果是,则将此消息发送到主窗体。 一旦表单将获得WM_LBUTTONDOWN事件,内置表单方法OnMouseDown和OnMouseMove执行其他工作。