Как рисовать графику максимально эффективно в WPF - PullRequest
18 голосов
/ 09 сентября 2011

Я создаю инструмент, который сильно зависит от деревьев узлов графа.Текущая реализация сделана на Java, и я портирую ее на общую кодовую базу на C #, поэтому она может использоваться различными реализациями рендеринга, а также потому, что я хочу использовать возможности WPF для удобного интерфейса.

После просмотра в течение дня я наткнулся на различные методы рисования векторной графики через WPF.

Этот парень говорит о разных слоях в WPF, которые могут выбирать разработчики.Поскольку я сначала хочу использовать WPF PURELY для его рендеринга, я хочу работать с «Визуальным слоем».

Затем я наткнулся на такие вещи, как: DrawingVisual , GeometryDrawing , FrameworkElement / UIElement / Shapes

Итак, я немного ошеломлен всеми различными реализациями, которые в конечном итоге делают то же самое совершенно разными способами.

Библиотека Graph-Node уже портирована на C # со всей ее логикой (включая обнаружение столкновений и перетаскивание мышью).Так как он сделан с учетом графических средств визуализации (таких как XNA, SlimDX, OpenTK и т. Д.), Каков наилучший способ с точки зрения производительности для реализации средства визуализации WPF (например, он будет рисовать все, что ему говорит библиотека графов)рисовать?

По сути, результирующий элемент управления WPF действует как холст, но он должен быть СУПЕР легким и не иметь каких-либо изящных функций WPF, кроме того, что дает мне возможность рисовать круги, линии и другие фигуры :)

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

Я в основном хочу знать: как идти?Должен ли я расширить Canvas в качестве «Хоста» для моей графики, а затем добавить свою собственную реализацию UIElement?Или я могу иметь один класс, который может рисовать ВСЁ (как, например, один мега супер ультра графический).Очень похоже на переопределение OnPaint в GDI или Paint-метод в Java (который дает объект Graphics, с которым можно все делать).

Ответы [ 3 ]

11 голосов
/ 09 сентября 2011

Я бы порекомендовал прочитать Оптимизация производительности: 2D-графика и обработка изображений (мертвая ссылка - читается через интернет-архив) -

Как правило, Drawing объекты будут легче, чем Shapes, в общем. Это, вероятно, то, что вы хотите использовать.

5 голосов
/ 02 июня 2013

Как правило, лучшая производительность достигается с помощью сервисов более низкого уровня.В WPF это означает семейство объектов Drawing.Все, что вы получаете: Drawing, DrawingGroup, GeometryDrawing, GlyphRunDrawing, ImageDrawing и VideoDrawing.Однако их достаточно для всех нужд.Использование этих типов очень удобно для WPF, потому что Drawing - это концептуальная единица, которую WPF обменивает с вашим ускорителем GPU, возможно сохраняя и управляя ею там, где это возможно.Это работает, потому что Drawing выражается в терминах переносимых примитивов векторного рисования.

Однако, как только вы начнете перестройку своего приложения вокруг Drawings, вам может потребоваться некоторое взаимодействие с вашим кодом более высокого уровня, которыйпо-прежнему основаны на UIElement, FrameworkElement и т. д. Одна вещь, которую я не нашел встроенной в WPF, - это простой способ обернуть чертеж как FrameworkElement минимально возможными накладными расходами.,DrawingVisual не является полным решением, поскольку оно происходит только от Visual - это означает, что для него по-прежнему требуется элемент размещения.

Следующий класс будет размещать любой WPF Drawing напрямую, без использования промежуточного DrawingVisual.Я добавил поддержку свойства FrameworkElement Margin (без потери производительности, если он не используется), но немного больше.Благодаря единому потоку рендеринга WPF безопасно и легко кэшировать один объект TranslateTransform для реализации поля.Я бы рекомендовал вам предоставлять только рисунки, которые были заморожены;фактически, в версии, которую я использую, у меня есть утверждение на этот счет в конструкторе.

public class DrawingElement : FrameworkElement
{
    static readonly TranslateTransform tt_cache = new TranslateTransform();

    public DrawingElement(Drawing drawing)
    {
        this.drawing = drawing;
    }
    readonly Drawing drawing;

    TranslateTransform get_transform()
    {
        if (Margin.Left == 0 && Margin.Top == 0)
            return null;
        tt_cache.X = Margin.Left;
        tt_cache.Y = Margin.Top;
        return tt_cache;
    }
    protected override Size MeasureOverride(Size _)
    {
        var sz = drawing.Bounds.Size;
        return new Size
        {
            Width = sz.Width + Margin.Left + Margin.Right,
            Height = sz.Height + Margin.Top + Margin.Bottom,
        };
    }
    protected override void OnRender(DrawingContext dc)
    {
        var tt = get_transform();
        if (tt != null)
            dc.PushTransform(tt);
        dc.DrawDrawing(drawing);
        if (tt != null)
            dc.Pop();
    }
};

[edit:] Это также полезно для вставки WPF Drawing в InlineUIContainer.Childсвойство (т. е. использование TextBlock.InlinesCollection для более полного форматирования содержимого TextBlock).

0 голосов
/ 09 сентября 2011

DrawingVisual представляется правильным выбором:

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

источник: Использование DrawingVisual объектов

так что это, кажется, абсолютно то, что вы просите, Canvas SUPER lightweight.

...