如何使用WPF避免抗锯齿?

时间:2009-12-16 23:20:30

标签: wpf antialiasing

WPF的一个重大问题是抗锯齿。 事实上,这就是WPF 4.0中引入 UseLayoutRending 的原因。 但是,在以下示例中,它对我不起作用:

<StackPanel UseLayoutRounding="True" TextOptions.TextFormattingMode="Display" >
    <Line X1="0" Y1="0" X2="200" Y2="0" StrokeThickness="1" Stroke="Black" SnapsToDevicePixels="True" UseLayoutRounding="True"></Line>
    <Line X1="0" Y1="1.5" X2="200" Y2="1.5" StrokeThickness="1" Stroke="Black" SnapsToDevicePixels="True" UseLayoutRounding="True"></Line>
    <Line X1="0" Y1="3.5" X2="200" Y2="3.5" StrokeThickness="1" Stroke="Black" SnapsToDevicePixels="True" UseLayoutRounding="True"></Line>
    <Line X1="0" Y1="7" X2="200" Y2="7" StrokeThickness="1" Stroke="Black" SnapsToDevicePixels="True" UseLayoutRounding="True"></Line>
    <Line X1="0" Y1="9" X2="200" Y2="9" StrokeThickness="1" Stroke="Black" SnapsToDevicePixels="True" UseLayoutRounding="True"></Line>
</StackPanel>

最后两行仍然模糊不清。 (我使用的是Windows 7)

任何解决方案?

或者它是WPF 4.0测试版中的错误?

4 个答案:

答案 0 :(得分:2)

Floele的答案显示了正确的方向,但答案并未完成。只需将y值设置为半个像素,例如Y1 =“7” - &gt; Y1 = “7.5”

这就是第二行和第三行没有模糊的原因。

答案 1 :(得分:2)

让WPF中的线条看起来很清晰可能会非常困难!有时......看起来它也需要一些黑魔法!

我认为floele和Kimke的答案指向了正确的方向。也就是说,通常你会想要将单个像素线放在0.5像素的边界上...给出它绘制线的方式(一边是一半,另一边是一半)。

但是,它并不总是那么简单。例如,它还取决于周围的xaml 。例如,尝试使用此代码并在执行此操作时调整大小:

<Canvas HorizontalAlignment="Center" VerticalAlignment="Center">
    <Line X1="0" Y1="5" X2="200" Y2="5" StrokeThickness="1" Stroke="Black" UseLayoutRounding="True"/>
    <Line X1="0" Y1="15" X2="200" Y2="15" StrokeThickness="1" Stroke="Black" UseLayoutRounding="True"/>
</Canvas>

然后,尝试使用此代码(再次,在执行时调整大小):

<Canvas HorizontalAlignment="Center" VerticalAlignment="Center" UseLayoutRounding="True">
    <Line X1="0" Y1="5" X2="200" Y2="5" StrokeThickness="1" Stroke="Black"/>
    <Line X1="0" Y1="15" X2="200" Y2="15" StrokeThickness="1" Stroke="Black"/>
</Canvas>

两个片段之间的唯一区别是第一个在Line上使用UseLayoutRounding,而第二个在Canvas容器上使用UseLayoutRounding(然后属性也继承到Lines)。

然而,这种差异产生了一些有趣的结果。当在容器上使用UseLayoutRounding时,单个像素线始终保持分布在2个像素上并且它们不会移动。当直接在线上使用UseLayoutRounding并调整大小时,线条有时会突出1个像素......其他时间将超过2个像素。

这让我想到了原始问题中的样本xaml。关于它的一些评论:

  1. 首先,您应该意识到UseLayoutRounding和SnapsToDevicePixels属性都会继承。也就是说,如果您在布局容器上使用它,它将继承到布局容器中的项目。
  2. UseLayoutRounding和SnapsToDevicePixels不一定要一起使用。它们可以......但我通常会尝试单独使用它们......无论是其中之一。更多信息:When should I use SnapsToDevicePixels in WPF 4.0?
  3. TextOptions.TextFormattingMode选项影响文本,而不影响行。
  4. 您用作布局容器的StackPanel也会影响线条的布局方式。 Canvas允许您对线条进行更精确的定位控制。 StackPanel将在另一行之后布置一行......并且可能会产生一些意想不到的结果。
  5. 比原始海报想要的更多信息。但是,我个人知道在WPF中获得线条是多么棘手。希望这些信息有助于某人!

答案 2 :(得分:1)

原因显然更简单。我只在“VB 2010中的Pro WPF”中找到了解释,而不是在MSDN上找到了解释:http://books.google.de/books?id=F-gMZkAlUDUC&pg=PA334&lpg=PA334

简而言之,StrokeThickness将被划分为形状的两边,因此StrokeThickness的1等于每边的0.5的厚度,并且因为线只有一边,所以将是0.5单位厚,因此即使使用SnapsToDevicePixels=True也会显得模糊。所以只需使用“2”作为StrokeThickness。

你可以使用4的StrokeThickness来验证这一点,然后该线的厚度为2,这不仅仅是一个“意外”的单像素偏差。

答案 3 :(得分:0)

您是否尝试将TextOptions.TextFormattingMode属性更改为Display?有关详细信息,请参阅Lester Lobo的this post