Sie dies, indem man zuerst das Abrufen das Drawing
Objekts tun kann, die das Aussehen der TextBlock
in der visuellen Struktur darstellt, und dann zu Fuß, dass die Suche nach GlyphRunDrawing
Elemente - diese enthalten den tatsächlich gerenderten Text auf dem Bildschirm. Hier ist eine sehr grobe und bereit Umsetzung:
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);
}
}
}
}
Dies ist ein direkter Auszug aus einem kleinen Test-Harnisch ich gerade geschrieben hätte - die erste Methode ist, einen Button-Klick-Handler nur für einfache Experimente.
Es verwendet die VisualTreeHelper
, um das gerenderte Drawing
für die TextBlock
- das wird nur funktionieren, wenn das Ding übrigens schon gerendert wurde. Und dann die WalkDrawingForText
Methode tut die eigentliche Arbeit - es durchquert nur die Drawing
Baum auf der Suche nach Text.
Das ist nicht besonders schlau - es geht davon aus, dass die GlyphRunDrawing
Objekte in der Reihenfolge erscheinen, in der Sie sie wollen. Für Ihr spezielles Beispiel - wir erhalten einen GlyphRunDrawing
, der den abgeschnittenen Text enthält, gefolgt von einem zweiten, der das Ellipsenzeichen enthält.(Und übrigens, es ist nur ein Unicode-Zeichen - Codepunkt 2026, und wenn dieser Editor mich Unicode-Zeichen einfügen lässt, ist es "...". Es ist nicht drei separate Perioden.)
Wenn Sie dies robuster machen wollten Sie müssten die Positionen all dieser GlyphRunDrawing
Objekte ausarbeiten und sortieren, um sie in der Reihenfolge zu verarbeiten, in der sie erscheinen, anstatt nur zu hoffen, dass WPF sie in dieser Reihenfolge erzeugt.
hinzufügen Aktualisiert:
Hier ist eine Skizze, wie ein Positions bewusst Beispiel aussehen könnte. Obwohl dies etwas engstirnig ist - es wird von links nach rechts gelesener Text angenommen. Sie würden etwas Komplexeres für eine internationalisierte Lösung benötigen.
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);
}
}
}
}
Ich würde gerne wissen, warum Sie das tun möchten ... – Guy
@Guy: Hehe, gute Frage :) Ich erstelle einen Effekt für den TextBlock, aber dazu brauche ich den angezeigten Text –