如何在 CefSharp.Wpf 中禁用“甩动/轻拂滚动”?

How can the 'fling/flick scrolling' be disabled in CefSharp.Wpf?

提问人:stoj 提问时间:9/4/2021 最后编辑:stoj 更新时间:9/13/2021 访问量:505

问:

有没有办法禁用 CefSharp.Wpf(或可能通过 Cef、Chromium 等)中的“触摸滚动”行为?

我很欣赏这是一个不寻常的请求,因为触摸滚动是一个很棒的功能。但不幸的是,我需要与一个狡猾的触摸屏硬件/驱动程序集成,它非常适合拖动。但在轻拂滚动时惨遭失败,因为它始终如一地“滚动”。例如,在屏幕上轻一拂会导致页面内容滚动多个页面(而不仅仅是几行)。

WPF Cefsharp 铬嵌入

评论

0赞 amaitland 9/4/2021
您究竟尝试过哪些命令行参数?值得一提的是,WPF 实现将触摸事件转发到底层 CEF 浏览器 github.com/cefsharp/CefSharp/blob/cefsharp/92/CefSharp.Wpf/...
0赞 stoj 9/4/2021
最初,尝试了几种与图形渲染相关的 chromium 设置,认为存在问题,例如 disable-gpu、disable-rtc-smoothness-algorithm、disable-low-res-tiling 等。然后,在通过将触摸屏控制器替换为更现代的东西(没有轻拂滚动问题)来确认这不是 CPU/图形问题后,我尝试了有关滚动的各种设置,例如禁用线程滚动、禁用平滑滚动、下拉刷新、禁用滚动到文本片段等。我已经通读了代码的那部分,看起来简单而扎实。
0赞 stoj 9/4/2021
我尝试过一件事,但取得了一些有限的成功。在处理 TouchAction.Up BEFORE 浏览器时添加了一个 Thread.Sleep(100)(我在路由事件中知道很糟糕)。GetHost()。调用 SendTouchEvent()。这停止了轻弹滚动。但它太骇人听闻了。
0赞 amaitland 9/4/2021
使用 chrome 时触摸屏的表现如何?相同还是更好?
0赞 stoj 9/4/2021
CefSharp.WebForm、Chrome、Chromium 和 Edge(都使用相同的引擎)都表现出完全相同的“过度滚动”问题。唯一的区别是 CefSharp.Wpf 需要 1 根手指才能进行甩动效果,而其他手指需要 2 根手指才能进行甩动效果(这可能是由于您之前引用的 CefSharp.Wpf 触摸实现)。

答:

1赞 stoj 9/13/2021 #1

没有 CefSharp/Cef/Chromium 标志或公共方法可用于取消 Chromium 的甩出行为。

幸运的是,在某些情况下,Chromium 确实会在内部取消甩动行为(请参阅 Chromium 的 fling_controller.cc)。其中一种情况是用户触地事件。

因此,诀窍是模拟触地取消事件对。由于 CefSharp 不提供“触地后”事件供用户实现逻辑(即过多的边缘情况),因此最简单的方法是通过派生类实现该功能。

这是一个完整的示例(带有依赖项属性绑定),以防它帮助其他人寻找相同的解决方案。

public class ChromiumWebBrowserEx : ChromiumWebBrowser
{
    public static readonly DependencyProperty IsFlingDisabledProperty = DependencyProperty.Register("IsFlingDisabled", typeof(bool), typeof(ChromiumWebBrowserEx));

    public bool IsFlingDisabled
    {
        get => (bool) GetValue(IsFlingDisabledProperty);
        set => SetValue(IsFlingDisabledProperty, value);
    }

    protected override void OnTouchUp(TouchEventArgs e)
    {
        base.OnTouchUp(e);

        if (IsFlingDisabled)
            CancelFling(e);
    }

    private void CancelFling(TouchEventArgs e)
    {
        // cancel the fling by creating a pseudo touch down followed by a cancellation
        var touchPoint = e.GetTouchPoint(this);
        if (touchPoint.Action == TouchAction.Up)
        {
            var touchEvent = new TouchEvent
                {
                    Id = e.TouchDevice.Id,
                    X = (float) touchPoint.Position.X,
                    Y = (float) touchPoint.Position.Y,
                    PointerType = PointerType.Touch,
                    Modifiers = WpfExtensions.GetModifierKeys(),
                    Type = TouchEventType.Pressed
                };

            GetBrowser().GetHost().SendTouchEvent(touchEvent);

            touchEvent.Type = TouchEventType.Cancelled;
            GetBrowser().GetHost().SendTouchEvent(touchEvent);
        }
    }
}