Ваш вопрос
Давайте перефразируем ваш вопрос. Это ваши проблемы ограничения:
- Вы хотите нарисовать сетку динамических размеров
- Каждая ячейка быстро включается / выключается
- Размеры сетки быстро меняются
- Существует большое количество ячеек (то есть размеры сетки не тривиальны)
- Вы хотите, чтобы все эти изменения происходили с высокой частотой кадров (например, 30 кадров в секунду)
- Расположение и расположение сетки и ячеек являются детерминированными, простыми и не очень интерактивными
Судя по этим ограничениям, сразу видно, что вы используете неправильный подход.
Требование: быстрое обновление детерминированных позиций с небольшой интерактивностью
Быстрое обновление частоты кадров + много изменений в кадре + большое количество ячеек + один объект WPF на ячейку = рассеиватель.
Если у вас не очень быстрое графическое оборудование и очень быстрый процессор, частота кадров всегда будет страдать с увеличением размеров сетки.
То, что диктует ваша проблема, больше похоже на видеоигру или программу для рисования в САПР с динамическим масштабированием. Это меньше похоже на обычное настольное приложение.
Немедленный режим против рисования в режиме удержания
Другими словами, вы хотите рисовать в «немедленном режиме», а не в «сохраненном режиме» (WPF - это режим хранения). Это связано с тем, что ваши ограничения не требуют большого количества функциональных возможностей, предоставляемых обработкой каждой ячейки как отдельного объекта WPF.
Например, вам не понадобится поддержка макета, потому что положение каждой ячейки детерминировано. Вам не понадобится поддержка тестирования при ударе, потому что, опять же, позиции являются детерминированными. Вам не понадобится поддержка контейнера, потому что каждая ячейка представляет собой простой прямоугольник (или изображение). Вам не понадобится сложная поддержка форматирования (например, прозрачность, округленные границы и т. Д.), Потому что ничего не перекрывается. Другими словами, нет смысла использовать Grid (или UniformGrid) и один объект WPF на ячейку.
Концепция рисования в непосредственном режиме в буферную битовую карту
Для достижения требуемой частоты кадров вы будете рисовать на большом растровом изображении (которое покрывает весь экран) - или в «экранном буфере». Для ваших ячеек просто используйте этот растровый / буферный буфер (возможно, используя GDI). Тестирование попадания легко, поскольку все ячейки детерминированы.
Этот метод будет быстрым, потому что есть только один объект (битовая карта экранного буфера). Вы можете либо обновить все растровое изображение для каждого кадра, либо обновить только те позиции экрана, которые меняются, или их разумную комбинацию.
Обратите внимание, что хотя вы рисуете здесь "сетку", вы не используете элемент "Сетка". Выберите свой алгоритм и свои структуры данных, основываясь на том, что представляют собой ограничения вашей проблемы, а не на том, как выглядит как очевидное решение - другими словами, «Сетка» может быть не правильным решением для рисования "сетка".
Рисование в непосредственном режиме в WPF
WPF основан на DirectX, поэтому по сути он уже использует растровое изображение буфера экрана (называемое обратным буфером) позади сцены.
Способ использования рисования в непосредственном режиме в WFP состоит в создании ячеек в виде GeometryDrawing (а не в Shape, что является режимом сохранения). GemoetryDrawing обычно очень быстр, потому что объекты GemoetryDrawing отображаются непосредственно на примитивы DirectX; они не размечаются и не отслеживаются по отдельности как элементы Framework, поэтому они очень легкие - их может быть много, что не влияет на производительность.
Выберите это GeometryDrawing в DrawingImage (это, по сути, ваш резервный буфер), и вы получите быстро меняющееся изображение для вашего экрана. За кулисами WPF делает именно то, что вы ожидаете, то есть рисует каждый прямоугольник, который изменяется на буфере изображения.
Опять же, не используйте Shape's - это элементы Framework, и будет накладывать значительные накладные расходы, так как они участвуют в макете.Например, НЕ ИСПОЛЬЗУЙТЕ Rectangle , но вместо этого используйте RectangleGeometry .
Оптимизации
Еще несколько оптимизаций, которые вы можете рассмотреть:
- Повторное использование объектов GeometryDrawing - просто измените положение и размер
- Если сетка имеет максимальный размер, предварительно создайте объекты
- Измените только те объекты GeometryDrawing, которые изменились - так что WPFне будет без необходимости обновлять их
- Заполните растровое изображение «стадиями» - то есть для разных уровней масштабирования всегда обновляйте сетку, которая намного больше предыдущей, и используйте масштабирование для ее уменьшения,Например, перейдите от сетки 10x10 непосредственно к сетке 20x20, но уменьшите ее на 55%, чтобы отобразить квадраты 11x11.Таким образом, при масштабировании от 11x11 до 20x20 ваши объекты GeometryDrawing никогда не изменяются;изменяется только масштабирование растрового изображения, что делает его чрезвычайно быстрым для обновления.
РЕДАКТИРОВАТЬ: делать покадровый рендеринг
Переопределить OnRender
, как указано в ответе, присуждаемом за вознаграждениена этот вопрос.Затем вы фактически рисуете всю сцену на холсте.
Используйте DirectX для абсолютного контроля
В качестве альтернативы, рассмотрите возможность использования необработанного DirectX, если вы хотите абсолютного контроля над каждым кадром.