Эквивалентный CreateGraphics в wpf

Итак, я использовал winForms .CreateGraphics, чтобы рисовать различные вещи, от линий до блоков и изображений. Это было очень быстро и отзывчиво.

Я пытаюсь выучить WPF на C#

Я обнаружил, что WPF позволяет мне "добавлять" прямоугольные объекты на холст, чтобы они отображались правильно. ОДНАКО, я рисую сотни тысяч прямоугольников время от времени, и скорость прорисовки может стать чрезвычайно медленной, и пользовательский интерфейс становится менее быстрым, когда я перемещаю хотя бы один из прямоугольников.

Рисование непосредственно на элемент в winForms было не очень быстрым, но оно было последовательным независимо от того, сколько я рисовал.

Есть ли подобное решение для этого в WPF?

Я пытался добавить linq к System.Drawing, который дал мне Graphics объект, но ни один из элементов wpf, которые я пробовал, не имеет .CreateGraphics() метод.

4 ответа

Решение

Вам нужно будет создать элемент управления, переопределяющий OnRender, и выполнять там свой рисунок. Вы не можете нарисовать другой элемент управления, но элемент управления может нарисовать сам.

Кроме того, имейте в виду, что WPF использует сохраненную графику, поэтому, если вы что-то измените, вам нужно будет сделать визуальную недействительной по мере необходимости.

РЕДАКТИРОВАТЬ:

Что-то вроде:

public class MyControl : Control {

    public MyControl() {
       this.Rects = new ObservableCollection<Rect>();
       // TODO: attach to CollectionChanged to know when to invalidate visual
    }

    public ObservableCollection<Rect> Rects { get; private set; }

    protected override void OnRender(DrawingContext dc) {
        SolidColorBrush mySolidColorBrush  = new SolidColorBrush();
        mySolidColorBrush.Color = Colors.LimeGreen;
        Pen myPen = new Pen(Brushes.Blue, 10);

        foreach (Rect rect in this.Rects)
            dc.DrawRectangle(mySolidColorBrush, myPen, rect);
    }
}

WPF использует другую модель для работы с графикой, чем WinForms.

С WinForms вы можете напрямую редактировать пиксели на экране. Понятие вашего прямоугольника теряется после прорисовки пикселей. Рисование пикселей - это очень быстрая операция.

С WPF вы не контролируете пиксели на экране. DirectDraw есть. DirectDraw - это векторный механизм композитинга. Вы не рисуете пиксели. Вы определяете векторные фигуры (или визуальные элементы). Концепция формы или прямоугольника сохраняется, даже после того, как изображение отображается на экране. Когда вы добавляете новый прямоугольник, который перекрывает другие, ВСЕ ДРУГИЕ прямоугольники должны быть перерисованы. Это, вероятно, где ваша производительность замедляется. Это не происходит при использовании WinForms.

Вы можете немного улучшить производительность WPF, переопределив OnRender. Вы можете вырезать накладные расходы на объект Rectangle и напрямую предоставить визуальные эффекты. Однако вы все еще не рисуете пиксели на экране. Вы определяете фигуры, которые DirectDraw использует для визуализации изображения. В связи с этим название OnRender может вводить в заблуждение.

Я уверен, что вы можете найти множество хитростей для повышения производительности вашего приложения в WPF. Есть способы по-прежнему рисовать пиксели, но это своего рода победа над WPF.

Что вы делаете, что требует тысячи прямоугольников?

Проблема, скорее всего, не в том, что WPF не может отображать тысячи графических объектов, а в том, что вы создаете и добавляете элементы слишком далеко в иерархии объектов WPF. В конце концов, он использует GPU для всей графической работы.

Вы должны добавлять объекты как можно ближе к классу "Visual", насколько это возможно, как только вы начинаете добавлять объекты на основе последнего "UIElement", вы просите WPF отслеживать клики пользователей, зависания и т. Д. Для каждого объекта, а не просто рисовать его.,

Как уже было сказано, WPF использует методологию сохранения графики, поэтому вы фактически создаете 100000 объектов Rectangle в памяти и затем рисуете их все. Замедление, вероятно, связано с сборкой мусора и общими проблемами с памятью.

Помимо переопределения метода OnRender, здесь есть пара вещей, на которые вы могли бы обратить внимание.

  1. Рисование прямоугольников на изображении в фоновом потоке с использованием знакомых вам методов GDI, а затем запись результата в WPF WriteableBitmap

  2. Используйте D3DImage и используйте аппаратное ускорение. Это требует, чтобы вы знали библиотеки DirectX (или Direct2D). Если вы заинтересованы в этом подходе, я бы посоветовал заглянуть в SlimDx.

Другие вопросы по тегам