猿问

在 WPF 画布中编写数千笔画的最佳方式

我必须通过在 Wacom 平板电脑(如在纸上)上触摸来实现书写,并且我需要在 WPF Canvas 中每秒渲染多达 200 个笔画。问题是,经过大约 20 秒的持续写入后,它会变得有点滞后,并且滞后会增加。我将所有笔画存储在HashSet 中。当 HashSet 包含超过 600 个元素并将其设置为背景图像并清除 HashSet 时,我想进行屏幕拍摄,但是在大约 30 次屏幕拍摄后它变得有点模糊。你知道如何让它变得更好吗?


慕的地8271018
浏览 232回答 1
1回答

MM们

您可以使用WriteableBitmap. 这非常快,但它通过将单个字节写入位图来工作,因此如果您需要将效果应用于绘图,那么您必须自己编写它们。这是一个如何使用WriteableBitmap. 在调试模式下,在我的计算机上的 1600 x 1200 像素图像上绘制 1000 条线(每条线由 1600 个点组成)需要大约 100 毫秒,但我确信这可以优化。我只是随机绘制线条,但您可以从Canvas触控笔获取事件并捕获其位置,并在每次笔画后传递它们。public partial class MainWindow : Window{&nbsp; &nbsp; private WriteableBitmap _bitmap;&nbsp; &nbsp; private readonly Random _random = new Random();&nbsp; &nbsp; private readonly Stopwatch _stopwatch = new Stopwatch();&nbsp; &nbsp; private const int White = 0x00000000;&nbsp; &nbsp; private const int Red = 0x00FF0000;&nbsp; &nbsp; private int _width;&nbsp; &nbsp; private int _height;&nbsp; &nbsp; public MainWindow()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; InitializeComponent();&nbsp; &nbsp; &nbsp; &nbsp; CanvasImage.Loaded += OnLoaded;&nbsp; &nbsp; }&nbsp; &nbsp; private async void OnLoaded(object sender, RoutedEventArgs e)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; _width = (int)DrawableCanvas.ActualWidth;&nbsp; &nbsp; &nbsp; &nbsp; _height = (int)DrawableCanvas.ActualHeight;&nbsp; &nbsp; &nbsp; &nbsp; _bitmap = new WriteableBitmap(_width, _height, 96, 96, PixelFormats.Bgr32, null);&nbsp; &nbsp; &nbsp; &nbsp; CanvasImage.Source = _bitmap;&nbsp; &nbsp; &nbsp; &nbsp; while (true)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; unsafe&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (var index = 0; index < _width * _height; index++)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *((int*)_bitmap.BackBuffer + index) = White;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _stopwatch.Start();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (var index = 0; index < 1000; index++)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var start = _random.Next(0, _width);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var points = Enumerable.Range(0, _width).Select(x => new Point((x + start) % _width, x % _height));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UpdateImage(points);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Debug.WriteLine($"Last 1000 draws took: {_stopwatch.ElapsedMilliseconds} ms");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _stopwatch.Reset();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; await Task.Delay(300);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; private void UpdateImage(IEnumerable<Point> points)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; _bitmap.Lock();&nbsp; &nbsp; &nbsp; &nbsp; foreach (var point in points)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var x = (int)point.X;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var y = (int)point.Y;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var offset = _width * y + x;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; unsafe&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *((int*)_bitmap.BackBuffer + offset) = Red;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; _bitmap.AddDirtyRect(new Int32Rect(0, 0, _width, _height));&nbsp; &nbsp; &nbsp; &nbsp; _bitmap.Unlock();&nbsp; &nbsp; }}并查看:<Grid>&nbsp; &nbsp; <Border Width="1604" Height="1204" BorderThickness="2" BorderBrush="Blue">&nbsp; &nbsp; &nbsp; &nbsp; <Canvas x:Name="DrawableCanvas">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <Image x:Name="CanvasImage"></Image>&nbsp; &nbsp; &nbsp; &nbsp; </Canvas>&nbsp; &nbsp; </Border></Grid>
随时随地看视频慕课网APP
我要回答