Как максимально эффективно рисовать графику в WPF

18

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

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

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

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

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

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

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

EDIT:

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

    
задан Lennard Fonteijn 09.09.2011 в 21:33
источник
  • См. meta.stackexchange.com/questions/2950/... –  John Saunders 09.09.2011 в 21:42
  • Сколько узлов вы ожидаете нарисовать на нормальном графике? –  Reed Copsey 09.09.2011 в 22:03
  • Сотни, по крайней мере. Графики динамически генерируются в итерациях. Каждая итерация может удвоить количество узлов. Я начинаю думать, что мне лучше использовать какую-то реализацию DirectX (с точки зрения отбраковки, возможно?). –  Lennard Fonteijn 09.09.2011 в 22:11
  • @ Lennard: Помните, WPF использует DirectX под капотом - вы получаете большую часть этого материала бесплатно. Canvas + Drawing будет легко масштабироваться до тысяч узлов (по крайней мере, в Vista +), хотя он использует DirectX, поэтому он зависит от видеокарты. –  Reed Copsey 09.09.2011 в 22:15

3 ответа

11

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

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

    
ответ дан Reed Copsey 09.09.2011 в 21:40
  • Я уже читал эту конкретную страницу, и это только меня смутило, что делать и что выбрать. Все описанные там методы все еще, похоже, подключены к фрейму слоя совсем немного, в то время как парень из Microsoft-блог специально упомянул визуальный слой без всяких причудливых вещей. –  Lennard Fonteijn 09.09.2011 в 21:43
  • Я в основном хочу знать: каков путь? Расширить ли Canvas как «Host» для моей графики, а затем добавить пользовательскую реализацию UIElement? Или у меня есть один класс, который может рисовать ВСЕ (как в одной мега супер ультра графике). Очень похоже на переопределение OnPaint в GDI или Paint-метод в Java (который дает объект Graphics делать все с). –  Lennard Fonteijn 09.09.2011 в 21:45
  • @ Lennard: «Визуальный слой» является частью фреймворческих слоев. Все в WPF использует и разделяется между визуальными и логическими деревьями. В вашем конкретном случае кажется, что вы хотите использовать GeometryDrawing и связанные классы. Это обеспечит вам чистый (относительно) легкий способ обработки чертежа ваших данных без большого количества других материалов, которые будут добавлены классами Shape *. –  Reed Copsey 09.09.2011 в 21:46
  • @ Lennard: Вы не будете думать об этом, как WinForms - вы просто используете Canvas и добавляете к нему объекты Drawing. WPF будет обрабатывать фактический рендеринг для вас и делать это достаточно эффективно, особенно если вы используете DrawingGroup, так как он кэширует вещи красиво. –  Reed Copsey 09.09.2011 в 21:46
  • @ Lennard: вы можете использовать Window.OnRender (msdn.microsoft.com/en-us/library/...). Однако использование рисунков обычно намного лучше для таких вещей. Каширование WPF, если вы используете DrawingGroup, обычно будет работать лучше, чем ваш собственный чертеж, как в Windows Forms / Java. Он кэширует и делает все через Direct3D, так что это довольно быстро. –  Reed Copsey 09.09.2011 в 22:01
Показать остальные комментарии
5

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

Как только вы начнете повторное архивирование своего приложения вокруг Drawings , вам может потребоваться некоторое взаимодействие с вашим кодом более высокого уровня, который по-прежнему зависит от UIElement , FrameworkElement и т. д. Одна вещь, найденный встроенным в WPF, - это простой способ обернуть Drawing как элемент Framework с наименьшим возможным способом. 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).

    
ответ дан Glenn Slayden 01.06.2013 в 22:23
0

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

  

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

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

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

    
ответ дан Davide Piras 09.09.2011 в 21:44
  • Пожалуйста, см. мои 2 замечания в ответе Рида. Я обновляю свой первый пост, чтобы задать вопрос еще более конкретным. –  Lennard Fonteijn 09.09.2011 в 21:47
  • DrawingVisual dows не кажется слишком высоким, насколько вы боитесь. если вы хотите быть еще более легким или родным, вы все равно можете пойти на OpenGL даже внутри WPF. Или прочитайте это также: stackoverflow.com/questions/1912469/directx-and-wpf –  Davide Piras 09.09.2011 в 21:49
  • Я знаю, что OpenGL / DirectX работает в WPF через D3DImage. Просто я хочу использовать WPF для рендеринга этого графика, поскольку он уже идет с методами рисования фигур, тогда как с XNA / Other мне придется сделать свою собственную библиотеку для этого и / или найти существующую (я знаю несколько , но поскольку WPF поддерживает это изначально, это по существу DirectX ...). –  Lennard Fonteijn 09.09.2011 в 21:55