You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF InkCanvas 编程创建Stroke时的性能问题求优化方案

WPF InkCanvas 屏蔽触摸/鼠标仅保留手写笔输入的性能优化方案

性能问题根源

你当前遇到的渲染滞后问题核心来自两个设计缺陷:

  • 每两个采样点就新建一个独立的Stroke实例,单次手写操作会生成几十上百个Stroke对象,每次插入StrokeCollection都会触发全量重绘,占用大量UI资源
  • 每次采样都触发一次Dispatcher.BeginInvoke,频繁的线程调度也会挤占UI渲染资源

核心优化方案

1. 复用单个Stroke追加点

你之前尝试追加新点的思路是正确的,已添加到StrokeCollection的Stroke完全支持追加新点:Stroke.StylusPoints本身实现了集合变更通知,新增点会自动触发局部重绘,不需要重建Stroke。你只需要新增一个私有字段存储当前正在绘制的Stroke实例即可。

2. 调整Dispatcher优先级

把Dispatcher操作的优先级设置为DispatcherPriority.Render,确保笔迹渲染优先于其他低优先级UI任务,减少调度延迟。

3. 优化后代码实现

// 新增类级别私有字段,存储当前正在绘制的笔划
private Stroke _currentDrawingStroke;

private void TabLib_DataReceived(object sender, EventArgs e)
{
    float pressureFactor = e.pressure / 1024f;
    StylusPoint newPoint = new StylusPoint(e.xPos, e.yPos, pressureFactor);

    // 手写笔抬起/离开场景,重置当前笔划
    if (pressureFactor == 0)
    {
        _currentDrawingStroke = null;
        return;
    }

    // 当前笔划的第一个点,新建Stroke并添加到集合
    if (_currentDrawingStroke == null)
    {
        var initialPoints = new StylusPointCollection { newPoint };
        _currentDrawingStroke = new Stroke(initialPoints, _penDrawingAttributes);
        // 高优先级调度添加笔划
        _tabletWindow.Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() =>
        {
            DrawnStrokes.Add(_currentDrawingStroke);
        }));
        return;
    }

    // 已有当前笔划,直接追加新点
    _tabletWindow.Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() =>
    {
        // 判空避免笔抬起后并发操作导致的异常
        if (_currentDrawingStroke != null)
        {
            _currentDrawingStroke.StylusPoints.Add(newPoint);
        }
    }));
}

补充优化建议

  • 如果手写笔采样率非常高,可以做简单的点聚合,比如每攒3-5个点再批量追加到StylusPoints,进一步降低调度频率
  • 若不需要支持笔划选中、擦除等交互,可以直接用DrawingVisual自定义渲染,性能比原生InkCanvas还要高30%以上
  • 你也可以不用设置HitTestVisible="False"绕路实现需求,直接过滤InkCanvas的路由事件即可,这种方式可以直接复用原生InkCanvas的渲染逻辑,性能最优:
// 直接屏蔽所有鼠标、触摸输入,仅保留手写笔输入
inkCanvas.PreviewMouseDown += (s, e) => e.Handled = true;
inkCanvas.PreviewMouseMove += (s, e) => e.Handled = true;
inkCanvas.PreviewMouseUp += (s, e) => e.Handled = true;
inkCanvas.PreviewTouchDown += (s, e) => e.Handled = true;
inkCanvas.PreviewTouchMove += (s, e) => e.Handled = true;
inkCanvas.PreviewTouchUp += (s, e) => e.Handled = true;

内容的提问来源于stack exchange,提问作者Marcel Grüger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 18:18:01