Mit einem kleinen Kniff kann aus Text ein Geometry-Objekt umgewandelt werden. Damit können einfach visuelle Effekte auf den Text angewandt werden. Dieser Beitrag zeigt, wie das in WPF funktioniert.

Die Anforderung, Text in ein Geometry-Element umzuwandeln, liegt schnell am Tisch. Dies beginnt bei speziellen Manipulationen (Verwendung von unterschiedlichen Brushes) und geht geht hin zu Performance- und Speicherthemen bei der Verwendung von Text in Shapes etc.

Die Umwandlung hierzu geht recht einfach:

var formattedText = new FormattedText("M", 
                    CultureInfo.CurrentCulture, 
                    FlowDirection.LeftToRight, 
                    new Typeface("Tahoma", 
                        FontStyles.Italic, 
                        FontWeights.Bold, 
                        FontStretches.Condensed), 
                    16, 
                    Brushes.Black);

var geometry = formattedText.BuildGeometry(new Point(5,5));

In diesem Fall ist das einfach nur der Buchstabe M im Font Tahoma, Schriftgröße 16, kursiv und fett. Spezielle Brushes kommen hier noch nicht zum Zuge.

Wichtig ist, dass der Text natürlich im Nachhinein nicht mehr geändert werden kann. Hierzu müsste das Geometry-Objekt neu erstellt werden.

Wer nun besonders viele dieser Geometry-Objekte zu erstellen hat und auch immer wieder dieselben Texte zum Zug kommen, der kann sich einfach behelfen.

public class TextGeometryBuilder
{
    private static Dictionary<string, Geometry> cachedGeometries = new Dictionary<string, Geometry>();

    public string Text { get; set; }
    public FontFamily FontFamily { get; set; }
    public FontStyle FontStyle { get; set; }
    public FontWeight FontWeight { get; set; }
    public FontStretch FontStretch { get; set; }
    public double FontSize { get; set; }
    public Point Origin { get; set; }

    public Geometry Geometry
    {
        get
        {
            if (cachedGeometries.ContainsKey(Text))
            {
                return cachedGeometries[Text];
            }

            var formattedText = new FormattedText(Text, 
                CultureInfo.CurrentCulture, 
                FlowDirection.LeftToRight, 
                new Typeface(FontFamily, FontStyle, FontWeight, FontStretch), 
                    FontSize, 
                    Brushes.Black);

            var geometry = formattedText.BuildGeometry(Origin);
            cachedGeometries.Add(Text, geometry);
            return geometry;
        }
    }

    public PathGeometry PathGeometry
    {
        get
        {
            return PathGeometry.CreateFromGeometry(Geometry);
        }
    }
}

Mit dieser Implementierung kann der TextGeometryBuilder auch via XAML verwendet werden. So kann man ihn als Ressource zur Verfügung stellen:

<ext:TextGeometryBuilder x:Key="MyGeometry" 
                         Text="M" 
                         FontFamily="Tahoma" 
                         FontSize="14" 
                         FontWeight="Bold" 
                         Origin="5,5"/>

Die eigentliche Besonderheit stellt aber der interne Cache dar. Dieser merkt sich die resultierenden Geometry-Objekte und die korrespondierenden Texte. Dadurch kann bei häufiger Verwendung mit gleichen Texten viel Zeit gespart werden. Unterschiedliche Konfigurationen für denselben Text sind in dieser Variante nicht vorgesehen.

Die definierte Ressource kann nun wie folgt verwendet werden (hier am Beispiel eines User Controls):

<Grid>
    <Ellipse 
    StrokeThickness="3"
    Stroke="Black" Fill="White"
        x:Name="Elli"/>
    <Path Data="{Binding Source={StaticResource MyGeometry}, Path=Geometry}" 
          Fill="Black"/>
</Grid>

Viel Spaß damit.

Über den Autor

Norbert Eder

Ich bin ein leidenschaftlicher Softwareentwickler und Fotograf. Mein Wissen und meine Gedanken teile ich nicht nur hier im Blog, sondern auch in Fachartikeln und Büchern.