Как улучшить производительность рендеринга Canvas? - PullRequest
11 голосов
/ 03 апреля 2012

Я должен нарисовать много Shape (около полутора тысяч) как дети [Canvas] [2].Я делаю это в своем приложении WPF, разделяя работу на две части: сначала я создаю фигуры, устанавливая свойства каждой из них (например, Margin, Fill, Width и т. Д.), После того, как добавляю фигуры в качестве потомков Canvas.

MyCanvas.Children.Add(MyShape)

Теперь я хочу улучшить производительность второй части, потому что, когда я рисую фигуры, мое приложение блокируется на длительный период времени.Поэтому я попытался использовать Dispatcher и его метод [BeginInvoke] [4] с разными [приоритетами] [5]: только если я использую приоритет фона, основное приложение не блокируется, в противном случае приложение остается заблокированными «картинка» не отображается, пока все фигуры не будут добавлены в мой холст, но если я использую приоритет фона, очевидно, что все будет медленнее.Я также пытался создать новый поток вместо использования Dispatcher, но никаких существенных изменений не произошло.

Как я могу исправить эту проблему и вообще улучшить производительность своего приложения при добавлении фигур в Canvas?

Спасибо.

Ответы [ 4 ]

7 голосов
/ 04 мая 2012

Необходимо использовать Визуальные объекты вместо Shape ; в частности, как было предложено, DrawingVisual : визуальный объект, который можно использовать для визуализации векторной графики. На самом деле, как написано в библиотеке MSDN:

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

Так, например, чтобы создать DrawingVisual, содержащий прямоугольник:

private DrawingVisual CreateDrawingVisualRectangle()
{
   DrawingVisual drawingVisual = new DrawingVisual();

   // Retrieve the DrawingContext in order to create new drawing content.
   DrawingContext drawingContext = drawingVisual.RenderOpen();

   // Create a rectangle and draw it in the DrawingContext.
   Rect rect = new Rect(new System.Windows.Point(160, 100), new System.Windows.Size(320, 80));
   drawingContext.DrawRectangle(System.Windows.Media.Brushes.LightBlue, (System.Windows.Media.Pen)null, rect);

   // Persist the drawing content.
   drawingContext.Close();

   return drawingVisual;
}

Чтобы использовать объекты DrawingVisual, вам необходимо создать хост-контейнер для объектов. Хост-контейнерный объект должен быть производным от класса FrameworkElement, который обеспечивает поддержку макета и обработки событий, отсутствующих в классе DrawingVisual. Когда вы создаете объект контейнера хоста для визуальных объектов, вам необходимо сохранить ссылки на визуальные объекты в VisualCollection .

public class MyVisualHost : FrameworkElement
{
   // Create a collection of child visual objects.
   private VisualCollection _children;

   public MyVisualHost()
   {
       _children = new VisualCollection(this);
       _children.Add(CreateDrawingVisualRectangle());

       // Add the event handler for MouseLeftButtonUp.
       this.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(MyVisualHost_MouseLeftButtonUp);
   }
}

Подпрограмма обработки событий может затем выполнить тестирование попаданий, вызвав метод HitTest . Параметр HitTestResultCallback метода относится к пользовательской процедуре, которую можно использовать для определения итогового действия теста на попадание.

3 голосов
/ 04 мая 2012

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

См. этот связанный вопрос , в котором подробно рассматривается высокопроизводительная графика в WPF и доступные альтернативы.

Если вам просто нужно использовать Canvas, проверьте это ZoomableApplication2 - миллион элементов . Это демонстрация на основе Canvas, которая интенсивно использует виртуализацию для достижения разумной производительности с 1 000 000 элементов UIE на Canvas.

1 голос
/ 26 мая 2014

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

У нас были некоторые проблемы с производительностью при использовании элемента управления Canvas для сбора подписей.Захват был очень неровным, и в результате мы не смогли нарисовать изогнутые линии.Оказалось, что это связано со стилем, который создавал тени на элементах пользовательского интерфейса.Отключение эффекта drop-shadow решило нашу проблему.

1 голос
/ 03 апреля 2012

Это много UIElements и, вероятно, не даст того вида производительности, который вы ищете. Нужно ли вам иметь возможность взаимодействовать с каждым из элементов, которые вы визуализируете? Если нет, я бы настоятельно рекомендовал использовать WriteableBitmap. Если вам нужно рисовать фигуры и вы не хотите создавать всю эту логику самостоятельно (кому бы это хотелось?), проверьте проект WriteableBitmapEx на CodePlex .

...