CefSharp中的可拖动无边界窗口 [英] Draggable borderless window in CefSharp

查看:873
本文介绍了CefSharp中的可拖动无边界窗口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在某些HTML元素上使用拖动逻辑实现无边界窗口。我找到了一些可行的示例(例如 Chrome的无框窗口)和这是我尝试过的:

I want to implement borderless window with drag logic on some HTML element. I found some working examples (like frameless window for Chrome) and this is what I've tried:

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

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

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

Then, in C# code I've implemented IDragHandler class:

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在启动时触发一次,当我拖动元素 title-区。但是我不确定下一步该怎么做才能使窗口移动?

Method OnDraggableRegionsChanged fires once at start, OnDragEnter fires when I'm dragging some text of the element "title-area". But I'm not sure what to do next to make my window move?

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

UPDATE. As mentioned in comments, CefTestApp support this drag feature. In the source code we have method OnSetDraggableRegions which is called from DragHandler:

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#的代码?

I'm still not quite understanding, how exactly information about dragable regions (which fires only once at start) helps to move window? Can someone explain me this logic or provide C# equivalent of this code?

推荐答案

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

UPDATE2. I DID IT. This is what I've added to my form code:

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));

                }
            });
        }
    }

如您所见,足以拦截WM_LBUTTONDOWN chrome浏览器触发事件​​,然后检查鼠标指针是否属于标题区域,如果是,则将此消息发送到主窗体。窗体一收到WM_LBUTTONDOWN事件,内置窗体方法OnMouseDown和OnMouseMove就会完成其他工作。

As you can see, it is enough to intercept WM_LBUTTONDOWN event from chrome browser, then check if mouse point belongs to a title region and, if so, send this message to main form. As soon as form will get WM_LBUTTONDOWN event, build-in form methods OnMouseDown and OnMouseMove do the other work.

这篇关于CefSharp中的可拖动无边界窗口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆