【问题标题】:TextBlock inside a Viewbox - strange renderingViewbox 内的 TextBlock - 奇怪的渲染
【发布时间】:2011-05-23 11:08:30
【问题描述】:

这是一个关于非常简单的构造的问题 - 我有以下 XAML:

    <Viewbox Height="100" Stretch="Uniform">
        <TextBlock FontFamily="Georgia">My Cool Text</TextBlock>
    </Viewbox>

这很容易理解。然而,当我启动程序时,我得到了奇怪的模糊文本(我的项目中没有任何位图效果)。

(左侧 - VS2010 中的设计器视图,右侧 - 正在运行的应用程序)

有人对为什么会发生这种情况有任何建议吗?

【问题讨论】:

  • 在我的机器上看起来也不错!!您使用的是什么版本的 WPF?你能在新窗口上测试它吗?因为它只是内容?
  • 是的,如果我创建一个只包含此代码的新应用程序看起来不错。我知道 :) 问题是我不知道我是如何做到这种模糊的拉伸的。某处有些东西,我不知道从什么开始。发布整个代码/资源字典也不是最好的主意 - 太多了。
  • 另外,viewbox 类型没有默认样式,TextBlock 的默认样式只是设置颜色。上面的代码完全来自我的 XAML。

标签: wpf viewbox


【解决方案1】:

好的,发现错误。我的 Window 样式具有以下设置器:

    <Setter Property="TextOptions.TextFormattingMode" Value="Display"/>

如果我将它设置回“理想”(这是默认值),那么它会正确呈现视图框中的文本。我会说这是 WPF 中的一个错误。基本上,如果你试试这个:

<Viewbox Height="100" Stretch="Uniform" TextOptions.TextFormattingMode="Display">
    <TextBlock FontFamily="Georgia">My Cool Text</TextBlock>
</Viewbox>

你会得到与我最初图片中相同的结果。

【讨论】:

    【解决方案2】:

    虽然 Jefim 正确回答了他自己的问题,但我想解释一下为什么在使用这组特定功能时会出现这种行为。 Jefim 认为这是 WPF 中的一个错误,但事实并非如此。问题是由于要求 WPF 做一些不可能的事情而出现的。当你要求这个不可能的事情时,它必须选择一个妥协,结果就是你在上面看到的。

    评论的解释有点长,这就是为什么我将它放在单独的答案中。

    这个例子使用了 WPF 的两个相互矛盾的特性。这些特点是:

    1. 能够以任何比例一致地呈现视觉效果
    2. 能够以与 GDI32 呈现文本相同的方式呈现文本

    您不能同时使用这两种功能。 GDI32 以无法一致缩放的方式呈现文本:如果特定字体大小的特定文本恰好是 200 像素宽,如果将字体大小乘以 3,并在同一字体系列中呈现相同的文本新的字体大小,在 GDI32 中它可能不会是 600 像素 - 它会接近,但通常不会完全正确。

    GDI32 会混淆字符的形状和宽度,以增强文本的清晰度和清晰度。具体来说,它会使字母变形,以便它们的特征与屏幕上的像素更好地对齐。必要时,它会将单个字符的宽度调整为精确的像素宽度。由于这种字母弯曲完全基于实际像素,因此它以不同的方式弯曲不同字体大小的文本。

    虽然这可以为您提供漂亮清晰的文本,但如果您尝试逐渐更改比例,它看起来绝对可怕。如果您尝试对以这种方式呈现的某些文本的字体大小进行动画处理,则该事物似乎会闪烁和颤抖,因为以清晰度为名所做的调整最终会在每种字体大小上略有不同。即使你没有制作动画,它仍然会产生很差的结果——如果你有一个字体以多种尺寸显示,那么在每种尺寸下它看起来可能会有很大的不同;如果您的应用程序具有缩放功能,则文本的字符在您放大和缩小时似乎会发生显着变化。 (布局也是如此。如果您使用 Microsoft Word,您可能已经注意到某些单词之间有时会出现看起来很奇怪的超宽空格。这是 Word 与 GDI32 对抗的结果 - Word 试图保持屏幕布局尽可能接近打印时的样子,这意味着它有时会与 GDI32 的网格拟合发生冲突。)

    因此 WPF 提供了一种不同的文本渲染方法:它可以以尽可能忠实于字体原始设计的方式渲染文本。这对文本的扭曲程度较小,这意味着您在缩放时不会出现不连续性。

    与 GDI32 呈现的文本相比,缺点是文本看起来模糊。 (GDI32所做的扭曲都是为了提高清晰度。)

    因此,在 WPF 4.0 中,Microsoft 添加了以 GDI32 的方式呈现文本的功能。这就是TextOptions.TextFormattingMode="Display" 所做的。

    通过打开该选项,您的意思是“我不需要一致的缩放比例,我更喜欢清晰度,因此生成与在 GDI32 中相同的像素。”如果您继续应用缩放,并告诉 WPF 您不需要可缩放性,您会得到糟糕的结果。 WPF 仔细生成了完全符合您的规范的文本的位图表示,然后您告诉它以不同的比例呈现该文本。所以它看起来就像是:为不同分辨率生成的某些文本的缩放位图。

    您可能会争辩说,WPF 在这里可以做一些不同的事情:如果您在 GDI32 中应用比例变换,您会看到不同的行为 - 您会看到前面描述的不同比例的不一致。如果你真的想要 WPF 中的那种效果,你可以通过直接修改字体大小来获得它。但 WPF 并不优先考虑获得相同的效果 - 它的目标是在您真正需要时获得 GDI32 风格的清晰文本,并在默认情况下提供一致的缩放。

    您在这里遇到的是“一致的缩放”。打开 GDI32 样式的文本渲染不会破坏一致的缩放:应用缩放因子(直接通过ScaleTransform 或间接通过Viewbox)将通过指定的缩放因子更改视觉对象的尺寸。如果要通过适合新缩放大小的网格重新生成文本视觉效果,文本将以不同的宽度出现。这实际上会导致Viewbox 问题:它根据内容的自然大小应用比例因子,旨在使其适合可用空间。但是如果它在缩放后重新调整网格,那实际上会改变宽度。由于 GDI32 文本渲染工作方式固有的不一致,ViewBox 甚至可能无法找到合适的比例 - 可能会想出一段文本,当以特定字体呈现时,永远不会200 像素宽。对于某些字体大小,网格拟合中固有的舍入可能会将大小降低到 198,并且当您对字体大小进行微小增量时它可能会一直保持不变,直到您超过某个阈值时它可能会跳跃到 202 像素。

    对于Viewbox 试图强制文本恰好适合 200 像素,这将是一个问题。但是Viewbox 不是这样工作的 - 它使用 WPF 的一致缩放,在您选择 GDI32 样式文本呈现工作的字体大小的点的下游。所以Viewbox 将始终能够完成它设计的任务,但这是与 GDI32 样式文本渲染根本不兼容的任务。

    简而言之,WPF 会根据您请求的字体大小呈现文本,然后缩放结果。

    因此,您必须只选择一项功能 - 您不能同时拥有这两种功能,因为那根本不可能。要么不要尝试在可以应用任意比例因子的上下文中渲染文本(例如Viewbox),要么不要打开 GDI32 样式的文本渲染。否则,你会得到你遇到的那种奇怪的像素化文本。

    【讨论】:

    • 感谢这个“评论”——读起来很有趣。我将其标记为答案,因为它是值得的。至于我对“错误”的表述-您的解释为我清除了一些东西。现在我只想说 - 这应该在 MSDN 文档上。真的,因为这不是那么明显(至少对我来说),我不得不花几个小时才能找到问题的原因。无论如何,再次感谢您的回答。
    • @lan Griffiths thx,我想知道是否可以获取 viewBox 中已更改其实际大小的元素?实际大小是屏幕中显示的元素而不是 ActualSize。我发帖stackoverflow.com/questions/42411455/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-13
    • 1970-01-01
    • 2015-09-05
    • 2014-02-15
    • 2023-03-21
    相关资源
    最近更新 更多