WPF - Shapes vs. DrawingVisual (производительность)
От: CyberSurfer  
Дата: 13.09.13 08:17
Оценка: :)
В MSDN написано:
DrawingVisual is a lightweight drawing class that is used to render shapes, images, or text. This class is considered lightweight because it does not provide layout, input, focus, or event handling, which improves its performance. For this reason, drawings are ideal for backgrounds and clip art.

Я написал код, рисующий тысячу линий с помощью объектов Line, и код, рисующий тысячу линий с помощью объектов DrawingVisual поверх изображения. Сравнивая производительность обоих способов я не увидел никакой разницы. Прокрутка итоговой картинки происходит недостаточно гладко в обоих случаях. Почему лаг при прокрутке итоговой картинки одинаковый в обоих случаях и где производительность класса DrawingVisual?

Первый способ (Line)

<ScrollViewer HorizontalScrollBarVisibility="Auto" 
              VerticalScrollBarVisibility="Auto">
    <Canvas Background="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"
            Name="layoutView">
        <Image>
            <Image.Source>
                <DrawingImage>
                    <DrawingImage.Drawing>
                            <ImageDrawing x:Name="testImage"/>
                    </DrawingImage.Drawing>
                </DrawingImage>
            </Image.Source>
        </Image>
    </Canvas>
</ScrollViewer>


ImageSource imageSource = new BitmapImage(uri);

testImage.Rect = new Rect(
    0, 0, imageSource.Width, imageSource.Height);
testImage.ImageSource = imageSource;

layoutView.Width = imageSource.Width;
layoutView.Height = imageSource.Height;

Random r = new Random();

int max = Math.Min(
    (int)imageSource.Height, (int)imageSource.Width);

for (int i = 0; i < 1000; i++)
{
    Point p1 = new Point(r.Next(max), r.Next(max));
    Point p2 = new Point(r.Next(max), r.Next(max));

    Line line = new Line();
    line.X1 = p1.X;
    line.Y1 = p1.Y;
    line.X2 = p2.X;
    line.Y2 = p2.Y;
    line.Stroke = Brushes.Red;

    layoutView.Children.Add(line);
}


Второй способ (DrawingVisual)

<ScrollViewer HorizontalScrollBarVisibility="Auto" 
              VerticalScrollBarVisibility="Auto">
    <my:VisualView Background="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"
                   x:Name="layoutView">
    </my:VisualView>
</ScrollViewer>


public class VisualView : Canvas
{
    List<Visual> visuals = new List<Visual>();

    protected override int VisualChildrenCount
    {
        get
        {
            return visuals.Count;
        }
    }

    protected override Visual GetVisualChild(int index)
    {
        return visuals[index];
    }

    public void AddVisual(Visual visual)
    {
        visuals.Add(visual);
        base.AddVisualChild(visual);
        base.AddLogicalChild(visual);
    }

    public void RemoveVisual(Visual visual)
    {
        visuals.Remove(visual);
        base.RemoveVisualChild(visual);
        base.RemoveLogicalChild(visual);
    }
}


ImageSource imageSource = new BitmapImage(uri);

Random r = new Random();

int max = Math.Min(
    (int)imageSource.Height, (int)imageSource.Width);

DrawingVisual dv = new DrawingVisual();
using (DrawingContext dc = dv.RenderOpen())
{
    dc.DrawImage(imageSource, new Rect(
        0, 0, imageSource.Width, imageSource.Height));
    dc.Close();

    layoutView.AddVisual(dv);

    layoutView.Width = imageSource.Width;
    layoutView.Height = imageSource.Height;
}

Pen pen = new Pen(Brushes.Red, 1);
for (int i = 0; i < 1000; i++)
{
    dv = new DrawingVisual();
    using (DrawingContext dc = dv.RenderOpen())
    {
        Point p1 = new Point(r.Next(max), r.Next(max));
        Point p2 = new Point(r.Next(max), r.Next(max));

        dc.DrawLine(pen, p1, p2);
        dc.Close();

        layoutView.AddVisual(dv);
    }
}



13.09.13 15:48: Перенесено модератором из '.NET' — TK
Re: WPF - Shapes vs. DrawingVisual (производительность)
От: MxMsk Португалия  
Дата: 13.09.13 09:55
Оценка:
Здравствуйте, CyberSurfer, Вы писали:

CS>Я написал код, рисующий тысячу линий с помощью объектов Line, и код, рисующий тысячу линий с помощью объектов DrawingVisual поверх изображения. Сравнивая производительность обоих способов я не увидел никакой разницы. Прокрутка итоговой картинки происходит недостаточно гладко в обоих случаях. Почему лаг при прокрутке итоговой картинки одинаковый в обоих случаях и где производительность класса DrawingVisual?

Ты выделил следствие, забыв о причинах. А именно: it does not provide layout, input, focus, or event handling. Т.е. DrawingVisual не участвует во всей этой катавасии, не нужной для "просто картинки", в то время как Line — это полноценный FrameworkElement, который опрашивается на хит-тест, который генерит события а-ля MouseEnter и т.п.

Далее касательно рендеринга. Очевидно же, что Line нарисует только одну линию. А на DrawingVisual, на одном DrawingVisual, ты можешь нарисовать сколько угодно этих линий. Вот тебе и performance. Если еще обрезать заведомо невидимые линии, то есть производительность может подняться еще выше.
Re: WPF - Shapes vs. DrawingVisual (производительность)
От: Sinix  
Дата: 13.09.13 10:44
Оценка:
Здравствуйте, CyberSurfer, Вы писали:

CS>

for (int i = 0; i < 1000; i++)
{
    dv = new DrawingVisual();
    using (DrawingContext dc = dv.RenderOpen())
    {
        Point p1 = new Point(r.Next(max), r.Next(max));
        Point p2 = new Point(r.Next(max), r.Next(max));

        dc.DrawLine(pen, p1, p2);
        dc.Close();

        layoutView.AddVisual(dv);
    }
}

1. Зачем 1000 раз создавать DrawingVisual?
2. Я бы заменил всё это дело на 1 DrawGeometry.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.