Skip to content

[Enhancement]: Cross-app — 172 body-text TextBlocks still write their size instead of using Caption/Subtle/SectionTitle, blocked on those five tokens missing BasedOn #1634

Description

@laurentiu021

Problem

Rewritten 2026-09-16 against current source. Every number below is re-derived from Views/*.xaml +
MainWindow.xaml with XAML comments stripped, counting <TextBlock> start tags only and excluding
elements that already name a Style or use an icon font (Segoe Fluent / Segoe MDL2, where a FontSize
is a glyph box rather than typography). 934 TextBlocks inspected. The original body counted every
FontSize="…" in the files, including icon glyphs, TextBox/ComboBox and style definitions, which is why
its totals cannot be compared with these.

The number half of this issue is finished. The body-text half is not, and it turns out to be blocked
on a prerequisite that has to be settled first.

What shipped

The scale now has twelve named styles, and all of them are used:

Token Size Uses
Subtle 12 200
Display 28 59
Body 13 59
SectionLabel 11 SemiBold 52
SectionTitle 14 44
Caption 11 19
MetricCompact 16 13
Metric 22 12
MetricLarge 26 8
Heading 20 5
MetricSmall 20 4
MetricHero 30 1

Metric rungs at 16 / 20 / 22 / 26 / 30, text at 28 / 20 / 14 / 13 / 12 / 11. Zero bare TextBlocks remain at
13, 18, 26, 28, 30 or 32. ArchitectureTests.EveryMetricRungSize_IsReachedThroughItsRung holds that line
and also asserts every rung a view names is actually defined, which a compile cannot tell you because
{StaticResource} inside a DataTemplate resolves at runtime.

Corrections to the original body

  • Heading was never dead. It has 5 uses today, and the claim was wrong when filed: the grep behind it
    searched for StaticResource Heading where the markup writes {StaticResource Heading}.
  • Metric did not "match no shipped value". It had 10 uses when filed and has 12 now. It was never
    re-pointed; instead the sizes the views actually drew got their own rungs, which is the change that made
    the scale describe the app rather than the reverse.
  • The 499/18 figures are not comparable to anything measurable, for the population reason above.

What is left

172 bare TextBlocks are drawn at a size that already has a token:

Raw size Token it should use Count Files
11 Caption 83 28
12 Subtle 67 26
14 SectionTitle 22 11

41 distinct view files are involved.

A further 48 sit at a size with no token at all: 10 (×24), 15 (×16), 9 (×7), 24 (×1 — About's product name,
deliberately left; no text rung sits within two points of it).

The prerequisite that blocks the sweep

Caption, Subtle, SectionTitle, SectionLabel and Display do not carry
BasedOn="{StaticResource {x:Type TextBlock}}". They restate Foreground and FontFamily instead. In WPF a
keyed style replaces the keyless <Style TargetType="TextBlock"> rather than merging with it, so applying
one of these five to an element that currently has no style silently drops the two setters they do not
restate:

<Setter Property="TextOptions.TextFormattingMode" Value="Ideal"/>
<Setter Property="TextOptions.TextRenderingMode" Value="ClearType"/>

So "swap FontSize="11" for Style="{StaticResource Caption}"" is not the no-op it looks like. Doing all
172 today would change the text-rendering mode on 172 elements.

The fix is one attribute on each of the five styles. It is also the one edit in this issue that is not free:
adding BasedOn to Display moves 59 tab titles from TextFormattingMode=Display (the WPF default they get
today) to Ideal. At 28px that is the mode you want — Ideal uses fractional glyph advances and is what the
rest of the app already renders with — but it is a real change on every tab's title, so it wants a look on a
machine that runs the app rather than a silent merge.

Proposed order

  1. Add BasedOn="{StaticResource {x:Type TextBlock}}" to Caption, Subtle, SectionTitle, SectionLabel
    and Display, and drop the setters that BasedOn then supplies. Verify with
    SysManager.IntegrationTests.TypographyTokenTests, which reads the resolved FontSize / FontWeight /
    Foreground off a real TextBlock on the STA thread — XAML compiles either way, so nothing else can tell.
    Screenshot check on the tab titles.
  2. Convert the 148 whose rendering the swap cannot change, so the edit is a size-attribute removal and
    nothing else: 78 at 11, 55 at 12, 15 at 14. Either they name their own Foreground (which beats the
    token's) or the token's colour is the TextPrimary they already inherit.
  3. Handle the remaining 24 individually, because each is a visible change and not a cleanup:
    • 17 name no Foreground and the token's differs from the inherited TextPrimary: 12 at 12 would become
      TextSecondary, 5 at 11 would become TextMuted.
    • 7 at 14 name no FontWeight, so SectionTitle's SemiBold would bolden them.
  4. Decide whether 10, 15 and 9 deserve tokens or should move onto 11 / 14. 24 stays raw unless the product
    name is up for discussion.

Step 1 is the merge-blocker for step 2. Steps 3 and 4 are per-site judgement, not a sweep.

Affected area

Cross-app — App.xaml typography block; 34 views.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestuxVisual or interaction improvement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions