如何在WPF中避免反锯齿?

4

在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 beta版本的错误吗?
4个回答

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>

两个片段之间唯一的区别在于第一个使用UseLayoutRounding在Lines上,而第二个使用UseLayoutRounding在Canvas容器上(然后也继承到了Lines)。
然而,这种差异产生了一些有趣的结果。当在容器上使用UseLayoutRounding时,单像素线始终保持在2个像素上分布,并且它们不会移动。当直接在Lines上使用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将仅在另一行后面布置一行...并可能产生一些意外的结果。
比原始帖子所需的信息更多。然而,我个人知道在WPF中如何使线条锐利是多么棘手。希望这些信息能对某人有所帮助!

2

Floele的回答指出了正确的方向,但答案并不完整。只需将y值设置为半个像素,例如Y1="7" -> Y1="7.5"

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


1

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

简而言之,StrokeThickness将被分为形状的两侧,因此StrokeThickness为1等于每侧0.5的厚度,由于线只有一侧,因此即使使用SnapsToDevicePixels=True,它也会有0.5个单位的厚度,从而看起来模糊。因此,只需使用“2”作为StrokeThickness

您可以通过使用StrokeThickness为4来验证这一点,那么该线将具有2的厚度,这比“偶然”的单像素偏差要大。


你的最后一句话不准确。如果你设置了一个4的StrokeThickness...它应该要么有一个4的描边厚度...或者它应该有一个3的描边厚度,中间的3个实心像素两侧各半个像素。 - cplotts
@cplotts 为什么不准确?在测试时是否得到了其他结果? - floele
非常肯定,@floele。我很想看看你所描述的一些示例代码。 - cplotts

0

你尝试过将 TextOptions.TextFormattingMode 属性更改为 Display 吗?请参考 Lester Lobo 的 这篇文章 了解详情。


我尝试了,但对我没有任何改变。你呢? - tom greene
老实说,我没有尝试过...... 我只是记得莱斯特博客上的那篇文章 ;) - Thomas Levesque
TextOptions.TextFormattingMode应该只适用于文本,以我的理解。这不应该影响其他事情。但是在使文本看起来更好方面非常有用! - cplotts

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接