您可以通过首先检索代表TextBlock
在可视树中外观的Drawing
对象,然后查找其中的GlyphRunDrawing
项来实现此操作 - 这些项将包含屏幕上实际呈现的文本。以下是一个非常简单的实现:
private void button1_Click(object sender, RoutedEventArgs e)
{
Drawing textBlockDrawing = VisualTreeHelper.GetDrawing(myTextBlock);
var sb = new StringBuilder();
WalkDrawingForText(sb, textBlockDrawing);
Debug.WriteLine(sb.ToString());
}
private static void WalkDrawingForText(StringBuilder sb, Drawing d)
{
var glyphs = d as GlyphRunDrawing;
if (glyphs != null)
{
sb.Append(glyphs.GlyphRun.Characters.ToArray());
}
else
{
var g = d as DrawingGroup;
if (g != null)
{
foreach (Drawing child in g.Children)
{
WalkDrawingForText(sb, child);
}
}
}
}
这是我刚刚编写的一个小测试工具的直接摘录 - 第一个方法是为了方便实验而编写的按钮点击处理程序。
它使用VisualTreeHelper
来获取TextBlock
的渲染Drawing
- 顺便说一下,如果该项已被渲染,则只会起作用。然后WalkDrawingForText
方法执行实际操作 - 它只是遍历Drawing
树查找文本。
这并不是非常智能 - 它假定您希望按照顺序出现GlyphRunDrawing
对象。对于您的特定示例,它可以 - 我们得到包含截断文本的一个GlyphRunDrawing
,后跟一个包含省略号字符的第二个GlyphRunDrawing
。(顺便说一下,这只是一个Unicode字符 - 码点2026,并且如果此编辑器允许我粘贴Unicode字符,则它是“…”。它不是三个单独的句点。)
如果您想使其更加健壮,那么您需要计算所有这些GlyphRunDrawing
对象的位置,并对它们进行排序,以便按照它们出现的顺序来处理它们,而不仅仅是希望WPF恰好以那个顺序产生它们。
更新内容:
这是一个位置感知示例的草图。虽然这有点狭隘 - 它假定从左到右阅读文本。您需要为国际化解决方案使用更复杂的内容。
private string GetTextFromVisual(Visual v)
{
Drawing textBlockDrawing = VisualTreeHelper.GetDrawing(v);
var glyphs = new List<PositionedGlyphs>();
WalkDrawingForGlyphRuns(glyphs, Transform.Identity, textBlockDrawing);
var glyphsOrderedByPosition = from glyph in glyphs
let roundedBaselineY = Math.Round(glyph.Position.Y, 1)
orderby roundedBaselineY ascending, glyph.Position.X ascending
select new string(glyph.Glyphs.GlyphRun.Characters.ToArray());
return string.Concat(glyphsOrderedByPosition);
}
[DebuggerDisplay("{Position}")]
public struct PositionedGlyphs
{
public PositionedGlyphs(Point position, GlyphRunDrawing grd)
{
this.Position = position;
this.Glyphs = grd;
}
public readonly Point Position;
public readonly GlyphRunDrawing Glyphs;
}
private static void WalkDrawingForGlyphRuns(List<PositionedGlyphs> glyphList, Transform tx, Drawing d)
{
var glyphs = d as GlyphRunDrawing;
if (glyphs != null)
{
var textOrigin = glyphs.GlyphRun.BaselineOrigin;
Point glyphPosition = tx.Transform(textOrigin);
glyphList.Add(new PositionedGlyphs(glyphPosition, glyphs));
}
else
{
var g = d as DrawingGroup;
if (g != null)
{
Matrix current = tx.Value;
if (g.Transform != null)
{
current.Append(g.Transform.Value);
}
var accumulatedTransform = new MatrixTransform(current);
foreach (Drawing child in g.Children)
{
WalkDrawingForGlyphRuns(glyphList, accumulatedTransform, child);
}
}
}
}