我有一个像这样定义的简单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:显示......”
由于
答案 0 :(得分:17)
您可以首先检索表示可视树中Drawing
外观的TextBlock
对象,然后查找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
来获取Drawing
的呈现TextBlock
- 只有在事物已经被渲染的情况下才会起作用。然后WalkDrawingForText
方法执行实际工作 - 它只遍历查找文本的Drawing
树。
这不是非常聪明 - 它假设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);
// Round vertical position, to provide some tolerance for rounding errors
// in position calculation. Not totally robust - would be better to
// identify lines, but that would complicate the example...
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)
{
// Drawing groups are allowed to transform their children, so we need to
// keep a running accumulated transform for where we are in the tree.
Matrix current = tx.Value;
if (g.Transform != null)
{
// Note, Matrix is a struct, so this modifies our local copy without
// affecting the one in the 'tx' Transforms.
current.Append(g.Transform.Value);
}
var accumulatedTransform = new MatrixTransform(current);
foreach (Drawing child in g.Children)
{
WalkDrawingForGlyphRuns(glyphList, accumulatedTransform, child);
}
}
}
}
答案 1 :(得分:10)
在我的Reflector周围生根了一段时间之后,我发现了以下内容:
System.Windows.Media.TextFormatting.TextCollapsedRange
,其Length
属性包含未显示的字符数(位于文本行的折叠/隐藏部分)。知道了这个值,只需要减法即可得到显示的字符。
无法从TextBlock对象直接访问此属性。看起来它是WPF用来在屏幕上实际绘制文本的代码的一部分。
实际上,为TextBlock中的文本行实际获取此属性的值可能会非常麻烦。
答案 2 :(得分:1)
嗯,这是一个特定的请求,所以我不确定框架中是否有现成的功能来执行此操作。我要做的是计算每个字符的逻辑宽度,将TextBlock的ActualWidth除以此值,并且您可以看到字符串开头可见的字符数。这当然是假设裁剪只会从右边发生。
答案 3 :(得分:1)
如果你需要一个效果的文本 - 那么它对渲染文本的图像是否足够? 如果是这样,你可以使用VisualBrush或System.Windows.Media.Imaging.RenderTargetBitmap
答案 4 :(得分:0)
我还在.Net框架上复制了以下xaml:
<Window x:Class="TestC1Grid.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
TextOptions.TextFormattingMode="Display"
TextOptions.TextRenderingMode="Auto"
ResizeMode="CanResizeWithGrip"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock TextTrimming="CharacterEllipsis"
FontFamily="Tahoma"
FontSize="12"
HorizontalAlignment="Stretch"
TextAlignment="Left" xml:lang="nl-nl">My-Text</TextBlock>
<TextBlock Grid.Column="1" TextTrimming="CharacterEllipsis"
FontFamily="Tahoma"
FontSize="12"
IsHyphenationEnabled="True">My-Text</TextBlock>
<TextBlock Grid.Column="2" TextTrimming="CharacterEllipsis"
FontFamily="Tahoma"
FontSize="12"
IsHyphenationEnabled="True">My-Text</TextBlock>
</Grid>
</Grid>
</Window>
如果你删除
TextOptions.TextFormattingMode = “显示”
TextOptions.TextRenderingMode =“自动”
或删除 XML:LANG = “NL-NL” 工作正常