1

我遇到了问题Tiling rectangles seamlessly in WPF中描述的问题,但对那里给出的答案并不满意。

我正在通过绘制许多彼此相邻的矩形来绘制条形图。根据包含它们的画布的比例,由于亚像素渲染,其中一些之间存在可见的小间隙。

我从上面的问题中学到了如何使我的矩形适合屏幕像素,消除这种效果。

不幸的是,我的图表显示的条形可能比像素多得多。除了微小的间隙(表现为颜色饱和度的周期性变化)之外,这效果很好。如果我用屏幕像素捕捉每个条,大多数条都会消失,所以我正在寻找另一种解决方案。

提前致谢!

4

1 回答 1

3

问题的原因

子像素形状在像素内使用 Alpha 混合。不幸的是,没有 alpha 混合算法可以使矩形在邻接时无缝混合。

例如,如果:

  • 背景颜色为白色
  • 前景色为黑色,并且
  • 你有两个矩形,每个矩形覆盖一个像素的一半

每个矩形将被涂成黑色,不透明度为 50%。第一个将白色像素转换为灰色。第二个将其转换为深灰色,但不是黑色。如果这些矩形在相邻像素中继续为黑色,您会在黑色中看到一个深灰色像素。

两种解决方案

解决这个问题的一般方法有两种:

  1. 使用单个 Geometry 来定义所有矩形,或
  2. 强制初始渲染具有足够高的分辨率,您的用户不会看到问题。

如何使用单个几何

如果您只有一组矩形,您可以创建一个简单的控件,该控件使用包含组合形状的单个 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" />

实现这一点的一种实用方法是:

  • 使用透明画笔绘制矩形,使其可点击但不可见
  • 按 Z 顺序在矩形下方添加路径控件
  • Data使用构造几何的转换器将 Path 控件的属性数据绑定到数据源。

如果您使用布局系统来定位矩形,您可能希望通过为每个矩形创建一个 Adorner 来使用 AdornerLayer,然后在渲染装饰器时计算第一个矩形的组合路径并使其余的不可见。

以上假设很容易从源数据生成 PathGeometry。对于更复杂的场景,可以对 Path 控件进行子类化,以在其父级的可视树中搜索指定的形状,并使用通用几何算法来计算 PathGeometry,该 PathGeometry 表示它们的并集,没有额外的边缘。

如果您的矩形将有多种颜色,您可以使用多个路径控件,每种颜色一个,或者您可以构建一个绘图对象并显示它。

下面是构造 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);

如何强制初始渲染为高分辨率

以更高分辨率强制渲染:

  1. 在内部构建比您想要显示的图表大几倍的图表,例如通过将其包装在 ViewBox 中。
  2. 使用 VisualBrush 或 RenderTargetBitmap 强制您的图表单独呈现
  3. 将使用该 VisualBrush 绘制的 Rectangle 添加到您的 UI

请注意,通常 WPF 在使用 ViewBrush 时以所需的实际分辨率进行渲染很聪明,但它可能会被实际图表以较大尺寸实际显示在屏幕上而被欺骗,但随后会被父控件剪裁,因此您不需要实际上并没有看到太大的版本。

当然,RenderTargetBitmap 不存在这个问题,因为您指定了所需的分辨率,但知道何时重新渲染位图可能会很棘手。如果您只重新渲染数据更改,您可以使用事件,但如果您希望任何视觉更改触发重新渲染,则更加困难。

于 2010-06-02T08:20:50.197 回答