эквивалентный CreateGraphics в wpf - PullRequest
6 голосов
/ 11 мая 2011

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

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

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

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

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

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

Ответы [ 4 ]

4 голосов
/ 11 мая 2011

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

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

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

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

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

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

2 голосов
/ 11 мая 2011

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

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

2 голосов
/ 11 мая 2011

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

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

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

2 голосов
/ 11 мая 2011

Вам нужно будет создать элемент управления, который переопределяет 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);
    }
}
...