从 TextBlock 获取显示的文本
我有一个像这样定义的简单 TextBlock
<StackPanel>
<Border Width="106"
Height="25"
Margin="6"
BorderBrush="Black"
BorderThickness="1"
HorizontalAlignment="Left">
<TextBlock Name="myTextBlock"
TextTrimming="CharacterEllipsis"
Text="TextBlock: Displayed text"/>
</Border>
</StackPanel>
输出如下
这会让我“TextBlock:显示的文本”
string text = myTextBlock.Text;
但是是有没有办法获取屏幕上实际显示的文本?
意思是“TextBlock:显示...”
谢谢
I have a simple TextBlock defined like this
<StackPanel>
<Border Width="106"
Height="25"
Margin="6"
BorderBrush="Black"
BorderThickness="1"
HorizontalAlignment="Left">
<TextBlock Name="myTextBlock"
TextTrimming="CharacterEllipsis"
Text="TextBlock: Displayed text"/>
</Border>
</StackPanel>
Which outputs like this
This will get me "TextBlock: Displayed text"
string text = myTextBlock.Text;
But is there a way to get the text that's actually displayed on the screen?
Meaning "TextBlock: Display..."
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您可以通过首先检索表示视觉树中
TextBlock
外观的Drawing
对象,然后遍历该对象查找GlyphRunDrawing
items - 这些将包含屏幕上实际呈现的文本。这是一个非常粗略且现成的实现:这是我刚刚编写的一个小测试工具的直接摘录 - 第一个方法是一个按钮单击处理程序,只是为了便于实验。
它使用
VisualTreeHelper
获取TextBlock
的渲染的Drawing
- 仅当事物已经渲染完毕时才有效。然后WalkDrawingForText
方法执行实际工作 - 它只是遍历Drawing
树查找文本。这并不是很聪明 - 它假设 GlyphRunDrawing 对象按照您想要的顺序出现。对于您的特定示例,它确实如此 - 我们得到一个包含截断文本的
GlyphRunDrawing
,后面跟着第二个包含省略号字符的 GlyphRunDrawing 。 (顺便说一句,它只是一个 unicode 字符 - 代码点 2026,如果这个编辑器让我粘贴 unicode 字符,它是“…”。它不是三个单独的句点。)如果您想让它更强大,您需要计算出所有这些 GlyphRunDrawing 对象的位置,并对它们进行排序,以便按照它们出现的顺序处理它们,而不是仅仅希望 WPF 碰巧按该顺序生成它们。
更新添加:
以下是位置感知示例的草图。尽管这有点狭隘——它假设从左到右阅读文本。您需要更复杂的东西来实现国际化解决方案。
You can do this by first retrieving the
Drawing
object that represents the appearance of theTextBlock
in the visual tree, and then walk that looking forGlyphRunDrawing
items - those will contain the actual rendered text on the screen. Here's a very rough and ready implementation:This is a direct excerpt from a little test harness I just wrote - the first method's a button click handler just for ease of experimentation.
It uses the
VisualTreeHelper
to get the renderedDrawing
for theTextBlock
- that'll only work if the thing has already been rendered by the way. And then theWalkDrawingForText
method does the actual work - it just traverses theDrawing
tree looking for text.This isn't terribly smart - it assumes that the
GlyphRunDrawing
objects appear in the order you'll want them. For your particular example it does - we get oneGlyphRunDrawing
containing the truncated text, followed by a second one containing the ellipsis character. (And by the way, it's just one unicode character - codepoint 2026, and if this editor lets me paste in unicode characters, it's "…". It's not three separate periods.)If you wanted to make this more robust, you would need to work out the positions of all those
GlyphRunDrawing
objects, and sort them, in order to process them in the order in which they appear, rather than merely hoping that WPF happens to produce them in that order.Updated to add:
Here's a sketch of how a position-aware example might look. Although this is somewhat parochial - it assumes left-to-right reading text. You'd need something more complex for an internationalized solution.
在围绕 I Reflector 研究了一段时间后,我发现了以下内容:
它有一个 Length 属性,其中包含未显示的字符数(位于文本行的折叠/隐藏部分)。知道该值后,只需进行减法即可获得显示的字符。
无法从 TextBlock 对象直接访问此属性。它看起来像是 WPF 用于在屏幕上实际绘制文本的代码的一部分。
要真正获取 TextBlock 中文本行的此属性的值,最终可能会花费大量时间。
After rooting around I Reflector for a while, I found the following:
which has a
Length
property that contains the number of characters that are NOT displayed (are in the collapsed/hidden portion of the text line). Knowing that value, it's just a matter of subtraction to get the characters that ARE displayed.This property is not directly accessible from the TextBlock object. It looks like it is part of the code that is used by WPF to actually paint the text on the screen.
It could end up being quite a lot of fooling around to actually get the value of this property for the text line in your TextBlock.
嗯,这是一个特定的请求,所以我不确定框架中是否有现成的函数可以做到这一点。我要做的是计算每个字符的逻辑宽度,将 TextBlock 的 ActualWidth 除以该值,然后得到从字符串开头开始可见的字符数。当然,这是假设剪切仅从右侧发生。
Well, it's a bit of a specific request so I'm not sure there's a ready made function in the framework to do it. What I would do is to calculate the logical width of each character, divide the ActualWidth of the TextBlock by this value and there you have the number of characters from the start of the string that are visible. That is of course assuming that clipping will only occur from the right.
如果您需要文本来实现效果 - 那么渲染文本的图像就足够了吗?
如果是这样,您可以使用 VisualBrush 或 System.Windows.Media.Imaging.RenderTargetBitmap
If you need the text for an effect - might it then be enough with the image of the rendered text?
If so you could use a VisualBrush or System.Windows.Media.Imaging.RenderTargetBitmap
接受的答案确实是正确的解决方案。现在,如果您想检查给定的
TextBlock
是否溢出,这里有一个扩展方法可以完成此任务。The accepted answer is indeed the right solution. Now, if you want to check if a given
TextBlock
has overflowed, here's an extension method that does exactly that.我还使用以下 xaml 在 .Net 框架上重现:
如果删除
TextOptions.TextFormattingMode="显示"
TextOptions.TextRenderingMode="Auto"
或删除
xml:lang="nl-nl"
工作正常
Also I reproduced on .Net framework with the following xaml:
if you remove
TextOptions.TextFormattingMode="Display"
TextOptions.TextRenderingMode="Auto"
or remove
xml:lang="nl-nl"
is working ok