WPF
text formatting
textblock
stroke
C#

Apply stroke to a textblock in WPF

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

TextBlock in WPF is great for lightweight text display, but it does not expose a built-in outline or stroke property. If you want text with both fill and border, the usual solution is to render text as geometry and then draw that geometry with a Fill and a Stroke.

Why TextBlock alone is not enough

TextBlock supports properties such as Foreground, wrapping, and inline formatting, but not text outlining. That means code like "set the stroke width of a TextBlock" has no direct API equivalent.

When you need outlined text, you typically switch from text layout primitives to shape drawing primitives. In WPF, the common approach is:

  1. build a text geometry
  2. show it inside a Path
  3. set Fill, Stroke, and StrokeThickness

Draw outlined text with FormattedText

The following custom control renders a string as geometry and then applies a fill and stroke.

csharp
1using System.Globalization;
2using System.Windows;
3using System.Windows.Media;
4using System.Windows.Shapes;
5
6public class OutlinedText : Shape
7{
8    public static readonly DependencyProperty TextProperty =
9        DependencyProperty.Register(
10            nameof(Text),
11            typeof(string),
12            typeof(OutlinedText),
13            new FrameworkPropertyMetadata(
14                string.Empty,
15                FrameworkPropertyMetadataOptions.AffectsRender |
16                FrameworkPropertyMetadataOptions.AffectsMeasure));
17
18    public string Text
19    {
20        get => (string)GetValue(TextProperty);
21        set => SetValue(TextProperty, value);
22    }
23
24    protected override Geometry DefiningGeometry
25    {
26        get
27        {
28            var formatted = new FormattedText(
29                Text ?? string.Empty,
30                CultureInfo.CurrentUICulture,
31                FlowDirection.LeftToRight,
32                new Typeface("Segoe UI"),
33                48,
34                Brushes.Black,
35                VisualTreeHelper.GetDpi(this).PixelsPerDip);
36
37            return formatted.BuildGeometry(new Point(0, formatted.Baseline));
38        }
39    }
40}

Use it in XAML:

xml
1<local:OutlinedText
2    Text="Outlined WPF Text"
3    Fill="White"
4    Stroke="Black"
5    StrokeThickness="2" />

Because OutlinedText derives from Shape, it inherits stroke-related properties naturally.

Simpler one-off approach with a Path

If you do not want a reusable control, create the geometry once and assign it to a Path.

csharp
1using System.Globalization;
2using System.Windows;
3using System.Windows.Media;
4using System.Windows.Shapes;
5
6var formatted = new FormattedText(
7    "Hello WPF",
8    CultureInfo.CurrentUICulture,
9    FlowDirection.LeftToRight,
10    new Typeface("Segoe UI"),
11    40,
12    Brushes.White,
13    VisualTreeHelper.GetDpi(this).PixelsPerDip);
14
15Geometry geometry = formatted.BuildGeometry(new Point(10, 50));
16
17var path = new Path
18{
19    Data = geometry,
20    Fill = Brushes.White,
21    Stroke = Brushes.DarkBlue,
22    StrokeThickness = 2
23};
24
25RootGrid.Children.Add(path);

This is often enough for splash screens, banners, or decorative text where you just need a small amount of outlined content.

When a fake outline is good enough

Sometimes you do not need true vector geometry. A quick visual effect can be made by layering several TextBlock elements slightly offset behind the main text.

That can work for prototypes, but it has drawbacks:

  • edges are less clean
  • alignment is harder
  • scaling looks worse than real geometry

For polished UI, geometry-based drawing is the better solution.

Layout and sizing considerations

When text becomes geometry, it no longer measures exactly like a regular TextBlock. That matters if the surrounding layout depends on automatic width and height.

If you build a custom control, make sure the geometry is regenerated when text, font, or DPI-related inputs change. Otherwise the outline can render with stale measurements.

Also remember that thick strokes extend beyond the fill shape. If the text sits near a container edge, the stroke may appear clipped unless you provide extra padding.

Common Pitfalls

The biggest mistake is trying to find a nonexistent Stroke property on TextBlock. WPF simply does not provide that feature on TextBlock itself.

Another issue is using FormattedText without the current DPI value. On modern systems, passing PixelsPerDip helps the rendered geometry stay consistent with the display scaling.

Developers also forget that outlined text is shape rendering, not ordinary text layout. That means wrapping, trimming, and inline formatting are no longer automatic the way they are with a TextBlock.

Finally, layered fake outlines may seem convenient, but they become fragile quickly once font size, animation, or scaling changes. Use geometry if the effect needs to be durable.

Summary

  • 'TextBlock does not support a true stroke or outline property.'
  • The usual WPF solution is to convert text to geometry and render it through a Path or custom Shape.
  • 'FormattedText.BuildGeometry() is the key API for outlined text.'
  • Geometry-based outlines look better and scale better than layered TextBlock hacks.
  • Account for DPI, layout, and stroke thickness when turning text into shapes.

Course illustration
Course illustration

All Rights Reserved.