自定义控件的性能很差 [英] Terrible performance of custom-drawn control

查看:87
本文介绍了自定义控件的性能很差的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在 wpf 中进行简单的图形控制。而且我无法解释或解决性能问题:与Winforms相比,它太慢了。也许我做错了。

I am making simple graph control in wpf. And I can't explain nor fix performance problem: it's too slow compared to winforms. Perhaps I am doing something wrong.

我准备演示演示该问题。

I prepare demo to demonstrate the problem.

这里是测试控件:

public class Graph : FrameworkElement
{
    private Point _mouse;
    private Point _offset = new Point(500, 500);

    public Graph()
    {
        Loaded += Graph_Loaded;
    }

    private void Graph_Loaded(object sender, RoutedEventArgs e)
    {
        // use parent container with background to receive mouse events too
        var parent = VisualTreeHelper.GetParent(this) as FrameworkElement;
        if (parent != null)
            parent.MouseMove += (s, a) => OnMouseMove(a);
    }

    protected override void OnRender(DrawingContext context)
    {
        // designer bugfix
        if (DesignerProperties.GetIsInDesignMode(this))
            return;

        Stopwatch watch = new Stopwatch();
        watch.Start();

        // generate some big figure (try to vary that 2000!)
        var radius = 1.0;
        var figures = new List<LineSegment>();
        for (int i = 0; i < 2000; i++, radius += 0.1)
        {
            var segment = new LineSegment(new Point(radius * Math.Sin(i) + _offset.X, radius * Math.Cos(i) + _offset.Y), true);
            segment.Freeze();
            figures.Add(segment);
        }
        var geometry = new PathGeometry(new[] { new PathFigure(figures[0].Point, figures, false) });
        geometry.Freeze();
        var pen = new Pen(Brushes.Black, 5);
        pen.Freeze();
        context.DrawGeometry(null, pen, geometry);

        // measure time
        var time = watch.ElapsedMilliseconds;
        Dispatcher.InvokeAsync(() =>
        {
            Window.GetWindow(this).Title = string.Format("{0:000}ms; {1:000}ms", time, watch.ElapsedMilliseconds);
        }, DispatcherPriority.Loaded);
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        base.OnMouseMove(e);
        var mouse = e.GetPosition(this);
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            // change graph location
            _offset.X += mouse.X - _mouse.X;
            _offset.Y += mouse.Y - _mouse.Y;
            InvalidateVisual();
        }
        // remember last mouse position
        _mouse = mouse;
    }
}

在xaml中如何使用它:

Here is how to use it in xaml:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525" WindowState="Maximized">
    <Grid Background="White">
        <local:Graph/>
    </Grid>
</Window>

一些说明:控件将绘制图形,可以用鼠标移动它:

Some remarks: control will draw figure, which can be moved by mouse:

它将在标题中显示2个测量值:首先是完成 OnRender()花费了多长时间,第二个是实际渲染花费了多长时间(第一次调用之后

It will display 2 measurements in title: first is how long it took for OnRender() to complete and second one is how long actual rendering took (first invoke after render).

尝试更改 2000 :设置 1000 使移动舒适, 3000 就像是在重新绘制图形之前(在我的PC上)延迟了半秒。

Try to vary that 2000: setting 1000 makes moving comfortable, 3000 is like half-second delay before figure is redrawn (on my PC).

问题:


  1. 使用 InvalidateVisual()更新 MouseMove 中的图形偏移量?如果不好,什么是使无效的正确技术呢?

  2. 冻结,其中许多冻结没有明显的效果。我是否需要使用它们?

  3. 看起来好像只需要 5ms 即可完成渲染,但是主观移动需要更长的时间(200毫秒以上)。为什么?

  1. Is it good to use InvalidateVisual() to update graph offset in MouseMove? And if bad, what is the right technique to invalidate?
  2. Freezes, there are many of them without any noticeable effect. Do I need to use them or not?
  3. It looks like it takes only 5ms to complete render, but moving subjectively takes much longer (200ms+). Why is that?

当然,主要问题是性能,为什么这么可怕?我可以在winform控制中画几万条线,直到变得草率,就像我的wpf控制只有1000条... =(

And main question is of course performance, why is it so terrible? I could draw few hundred thousands of lines in winform control until it become as sloppy, as mine wpf control does with just 1000... =(

我找到了最后一个问题的答案,用鼠标移动时渲染时间的测量无法正常工作,但是如果调整了窗口大小,则第二次变为 300ms (在我的PC上有 2000 个数字)。所以这不是错误的鼠标失效(第一个问题),但渲染速度确实很慢。 / p>

I found an answer on last question. Measuring of rendering time doesn't works correctly when moving with mouse. But if window is resized, then second time become 300ms (on my PC with 2000 figures). So it's not a wrong mouse invalidate (first question), but indeed very slow rendering.

推荐答案

这很奇怪,这里没有人提及,但是可以在wpf中使用gdi draw原生(无需托管容器)。

It's strange and nobody here mentioned, but it is possible to use gdi draw in wpf natively (without hosting container).

I首先发现这个问题,该问题成为基于渲染的普通图形(使用 InvalidateVisuals()重画)。

I found this question first, which become normal render-based graph (use InvalidateVisuals() to redraw).

protected override void OnRender(DrawingContext context)
{
    using (var bitmap = new GDI.Bitmap((int)RenderSize.Width, (int)RenderSize.Height))
    {
        using (var graphics = GDI.Graphics.FromImage(bitmap))
        {
            // use gdi functions here, to ex.: graphics.DrawLine(...)
        }
        var hbitmap = bitmap.GetHbitmap();
        var size = bitmap.Width * bitmap.Height * 4;
        GC.AddMemoryPressure(size);
        var image = Imaging.CreateBitmapSourceFromHBitmap(hbitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
        image.Freeze();
        context.DrawImage(image, new Rect(RenderSize));
        DeleteObject(hbitmap);
        GC.RemoveMemoryPressure(size);
    }
}

这种方法能够绘制数十万条线。

This approach is capable to draw hundred thousands of lines. Very responsive.

缺点:


  • 不像纯gdi那样光滑图中的 DrawImage 会出现一段时间,然后会闪烁。

  • 将所有wpf对象转换为gdi对象所必需(有时是不可能的) ):钢笔,画笔,点,矩形等。

  • 没有动画,图形本身可以动画化(例如进行变换),但是图形不能动画。

  • not as smooth, as pure gdi one graph, DrawImage occurs some times after, will flickers a bit.
  • necessary to convert all wpf objects to gdi ones (sometimes is impossible): pens, brushes, points, rectangles, etc.
  • no animations, graph itself can be animated (to example, transformed), but drawings are not.

这篇关于自定义控件的性能很差的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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