【问题标题】:Draggable borderless window in CefSharpCefSharp 中的可拖动无边框窗口
【发布时间】:2016-07-03 09:47:37
【问题描述】:

我想在一些 HTML 元素上实现带有拖动逻辑的无边框窗口。我找到了一些工作示例(例如frameless window for Chrome),这就是我尝试过的:

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

<div class='title-area'>
    A draggable area
</div>

然后,我在 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<DraggableRegion> regions)
    {

    }
}

方法 OnDraggableRegionsChanged 在开始时触发一次,当我拖动元素“标题区域”的某些文本时触发 OnDragEnter。但我不确定下一步该怎么做才能让我的窗口移动?

更新。 如 cmets 中所述,CefTestApp 支持此拖动功能。在源代码中,我们有从 DragHandler 调用的方法 OnSetDraggableRegions:

void RootWindowWin::OnSetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) {
REQUIRE_MAIN_THREAD();

// Reset draggable region.
  ::SetRectRgn(draggable_region_, 0, 0, 0, 0);

  // Determine new draggable region.
  std::vector<CefDraggableRegion>::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<LPARAM>(draggable_region_));
  }
}

我还是不太明白,关于可拖动区域(在启动时只触发一次)的确切信息如何帮助移动窗口?有人可以解释一下这个逻辑或提供与此代码等效的 C# 代码吗?

【问题讨论】:

  • 检查cefclient 示例应用程序,内存中有一个工作示例,您应该可以将其移植过来。 bitbucket.org/chromiumembedded/cef/src/…
  • @amaitland,是的,你是对的 - 它确实支持 grag 功能(至少 Windows 应用程序)。但我不明白它究竟是如何工作的。我已经更新了我的问题。
  • 尝试调试代码,看看它是如何工作的
  • @amaitland,完成。如果您有兴趣,请查看来源。
  • 谢谢,如果您发布自己的问题的答案可能会更好。

标签: c# drag cefsharp borderless


【解决方案1】:

看看:https://github.com/qwqcode/CefSharpDraggableRegion

您可以在 CSS 中指定 -webkit-app-region: drag 来告诉 CefSharp 哪些区域是可拖动的(如操作系统的标准标题栏)。

【讨论】:

    【解决方案2】:

    更新2。我做到了。这是我添加到表单代码中的内容:

    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 就会完成其他工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-07
      • 2016-10-09
      • 2016-02-03
      • 1970-01-01
      • 1970-01-01
      • 2014-09-22
      • 1970-01-01
      相关资源
      最近更新 更多