dotnet / dotnet/winforms

[Tracking] Modern field stroke state model for Net11 editable controls (TextBoxBase)

Open
#14,906 8 comments 0 reactions 1 assignee Claimed by @ricardobossan View on GitHub
NewApi-Net11 rendering-or-artifacts-issues
Dominant language
C#
Stars
4.9k
Forks
1.1k
Avg merge
1d 13m
Merged PRs (30d)
85

Description

### Goal

Replace the current flat, ForeColor-driven border and the primitive bottom-clipped focus ring on VisualStylesMode.Net11 editable controls with a proper per-state stroke model: a WinUI-style elevation border with distinct Rest, Hover, Focused, Disabled, and ReadOnly treatments; colors derived independently of ForeColor via linear-light overlay compositing; a stronger and thicker bottom elevation edge; an accent focus edge at >= 2 DIP; and hover tracking. High Contrast uses system colors. This issue is the tracking item and definition of done for that work.

### Current state (base af0c793d5)

Editable controls under Net11 (TextBox, MaskedTextBox, RichTextBox, all via TextBoxBase) paint their modern non-client frame in `TextBoxBase.OnNcPaint`:

- One flat stroke: the border color is the control's `ForeColor` (`adornerColor = ForeColor`), one pen, one thickness on all four sides. No elevation edge.
- Focus is a bottom-clipped copy of the same rounded stroke at the same thickness, color animated `ForeColor` -> accent (`AnimatedFocusIndicatorRenderer.DrawRoundedFocusIndicator`). FixedSingle uses repeated horizontal bottom lines.
- Rest, Hover, Disabled, and ReadOnly are visually identical (all `ForeColor`); Hover is not tracked.
- The existing shared blend (`PopupButtonColorMath.Blend`) interpolates encoded sRGB, so it cannot produce perceptually-correct overlays; new linear-light math is required.

### Scope

TextBoxBase's Net11 non-client paint path: TextBox, MaskedTextBox, RichTextBox.

### Out of scope (separate follow-ups)

- ComboBox: a WM_PAINT client-area adapter, not an NC-paint caller.
- UpDownBase / UpDownEdit: separate client-area implementation.
Coordinate a shared visual target with these so a TextBox does not diverge from an adjacent ComboBox or NumericUpDown.

### Plan (one migration step at a time)

Behavior-preserving refactor first (Steps 1 and 2), then the one visible change (Step 3). The step and sub-step labels below are the reference scheme used across the linked PRs and comments.

**Step 1: Introduce the model, wired to nothing.** Add a `ModernFieldStrokeState` enum, a `ModernFieldStroke` record, a context, a `GetStroke` resolver (state precedence Disabled > Focused > ReadOnly > Hover > Rest), and a per-control cache, with a compatibility mapping that reproduces today's pixels, plus unit tests. No paint path calls it; zero visual diff.

**Step 2: Route the paint through the resolver.** Change `TextBoxBase.OnNcPaint` to obtain its stroke from `GetStroke`, with the compatibility mapping still on. Still zero visual diff (prove it with a pixel baseline captured before this step).

**Step 3: Apply the real visuals.** Deliverable 1 does this as a single commit; proposed here as three independently reviewable sub-steps:

- **Step 3a (color model):** remove ForeColor from the stroke, add linear-light overlay compositing, and apply the Rest, Disabled, and ReadOnly colors, plus the High Contrast bypass.
- **Step 3b (focus):** the accent-colored bottom edge and the DPI-scaled focus thickness (at least 2 DIP).
- **Step 3c (hover):** the new hover tracking and repaint, plus the Hover state color.

### Open decisions

- High Contrast focus color: keep `SystemColors.Highlight` (current) vs switch to `SystemColors.ControlText`. Accessibility-affecting; recommend keeping Highlight unless validated.
- Focus thickness: `max(2 DIP, configured focus metric)`; and whether the thickness change snaps or animates (color already animates 200 ms).
- Hover detection mechanism for the non-client border.
- Shared visual target with the out-of-scope ComboBox / UpDown.

### Related

- #14847: ForeColor incorrectly affects the border color of editable controls (the narrow resting-color slice).
- #14853: fixes #14847 by replacing `ForeColor` with a shared `ModernControlColorMath.TextControlBorderColor` in TextBoxBase, ComboBox.ModernComboAdapter, and UpDownBase. This is the first narrow step of this task and should land first; afterward, Step 1's compatibility mapping rebaselines its resting and disabled endpoints onto `TextControlBorderColor` / `GetDisabledBorderColor`.
- #14792: introduced Net11 editable-control rendering (origin).
- A design/analysis (Deliverable 1) informed this plan.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.