причина проблемы
В субпиксельных фигурах используется альфа-смешение внутри пикселя. К сожалению, не существует алгоритма альфа-смешивания, который бы приводил к плавному смешиванию прямоугольников при стыковке.
Например, если:
- Цвет фона белый
- Цвет переднего плана черный, а
- У вас есть два прямоугольника, каждый из которых покрывает половину одного пикселя
Каждый прямоугольник будет окрашен в черный цвет с непрозрачностью 50%. Первый преобразует белый пиксель в серый. Второй преобразует его в более темный серый, но не черный. Если эти прямоугольники продолжают оставаться черными в смежных пикселях, то среди черного вы видите темно-серый пиксель.
Два типа решений
Существует два основных способа решения этой проблемы:
- Используйте одну геометрию для определения всех ваших прямоугольников или
- Принудительно установить начальный рендеринг с достаточно высоким разрешением, чтобы ваш пользователь не увидел проблему.
Как использовать одну геометрию
Если у вас есть только набор прямоугольников, вы можете создать простой элемент управления, который закрашивает весь набор прямоугольников с помощью одной PathGeometry, содержащей комбинированную форму. Чтобы проиллюстрировать идею, если у вас было два прямоугольника рядом друг с другом разной высоты, например:
<Rectangle Canvas.Left="0" Canvas.Top="0" Width="1.5" Height="2" Fill="Red" />
<Rectangle Canvas.Left="1.5" Canvas.Top="0" Width="1.5" Height="4" Fill="Red" />
Вы можете отобразить его с помощью одной PathGeometry, например так:
<Path Data="M0,0 L0,2 L1.5,2 L1.5,4 L3,4 L3,0 Z" Fill="Red" />
Практический способ реализовать это:
- Нарисуйте свои прямоугольники прозрачной кистью, чтобы они были кликабельными, но не видимыми
- Добавить элемент управления Path под прямоугольниками в Z-порядке
- Привязка данных к свойству
Data
элемента управления Path к источнику данных с помощью преобразователя, который создает геометрию.
Если вы используете систему макетов для позиционирования ваших прямоугольников, вы можете вместо этого использовать AdornerLayer, создав Adorner для каждого прямоугольника, а затем при рендеринге украшателей вычислить объединенный путь для первого и сделать остальные невидимыми.
Выше предполагается, что легко сгенерировать PathGeometry из исходных данных. Для более сложных сценариев элемент управления Path может быть разделен на подклассы для поиска в визуальном дереве его родителя указанных фигур и использования общих геометрических алгоритмов для вычисления PathGeometry, который представляет их объединение без лишних ребер.
Если ваши прямоугольники будут иметь несколько цветов, вы можете использовать несколько элементов управления Path по одному на цвет или создать объект Drawing и показать это.
Вот структура кода для построения PathGeometry:
var geo = new PathGeometry();
var figure = new PathFigure();
var segment = new PolyLineSegment();
segment.Points.Add(...);
segment.Points.Add(...);
segment.Points.Add(...);
segment.Points.Add(...);
segment.Points.Add(...);
figure.Segments.Add(segment);
geo.Figures.Add(figure);
Как заставить исходный рендеринг иметь высокое разрешение
Для принудительного рендеринга с более высоким разрешением:
- Внутреннее построение диаграммы в несколько раз больше, чем вы хотите отобразить, например, оборачивая ее в ViewBox.
- Используйте VisualBrush или RenderTargetBitmap, чтобы заставить вашу диаграмму отображаться отдельно
- Добавьте прямоугольник, нарисованный этим VisualBrush, в ваш пользовательский интерфейс
Обратите внимание, что обычно WPF умен при рендеринге с фактическим разрешением, требуемым при использовании ViewBrush, но его можно обмануть, если фактическая диаграмма будет отображаться на экране с большим размером, но затем обрезаться родительским элементом управления. так что вы на самом деле не видите слишком большую версию.
Эта проблема, конечно же, не существует с RenderTargetBitmap, так как вы указываете нужное разрешение, но может быть сложно понять, когда повторно визуализировать растровое изображение. Если вы выполняете повторную визуализацию только при изменениях данных, вы можете использовать событие, но если вы хотите, чтобы какое-либо визуальное изменение вызвало повторную визуализацию, это сложнее.