[API Proposal] Introduce ISymbol and ToolStrip Symbol support
- Dominant language
- C#
- Stars
- 4.9k
- Forks
- 1.1k
- Avg merge
- 1d 13m
- Merged PRs (30d)
- 85
Description
# Background and motivation
WinForms ToolStrip APIs are image-centric, while modern applications increasingly need semantic, reusable symbols backed by vectors, font glyphs, bitmaps, or future sources. Applications currently rasterize those assets independently, losing reusable accessibility metadata and duplicating DPI/theme-aware caching.
A backend-neutral symbol contract would let ToolStrip consume semantic assets without binding WinForms to SVG, GDI+, Direct2D, or a particular renderer. WARP has been used as an experimental implementation proving the layering, but this proposal stands alone and does not require a WARP dependency.
# API Proposal
```csharp
namespace System.Windows.Forms;
public interface ISymbol
{
string? AccessibilityName { get; set; }
string? AccessibilityDescription { get; set; }
Size GetPreferredSize(Size proposedSize);
}
public partial class ToolStripItem
{
public ISymbol? Symbol { get; set; }
}
```
`ISymbol` describes the asset, not its rendering backend. Renderer discovery and caching remain separate so application-defined symbol types and future rendering backends can be added without changing the interface.
Proposed sizing semantics:
- `Size.Empty` requests the symbol's natural/default size.
- One zero dimension leaves that axis unconstrained.
- Two positive dimensions constrain the result; aspect-preserving symbols fit within them.
Proposed coexistence rule: a non-null, renderable `Symbol` wins over `Image`, but does not destroy the assigned `Image`; clearing `Symbol` restores normal image behavior.
Proposed accessibility fallback:
```text
ToolStripItem.AccessibleName
↓ if unset
ISymbol.AccessibilityName
↓ if unset
existing WinForms fallback
```
and equivalently for `AccessibleDescription`. The hosting item always remains authoritative.
Current image-centric source paths:
- [`ToolStripItem.PreferredImageSize`](https://github.com/dotnet/winforms/blob/f724c2277a0695ca71d1816575636afc802d73b9/src/System.Windows.Forms/System/Windows/Forms/Controls/ToolStrips/ToolStripItem.cs#L1552-L1575)
- [`ToolStripMenuItem` image layout](https://github.com/dotnet/winforms/blob/f724c2277a0695ca71d1816575636afc802d73b9/src/System.Windows.Forms/System/Windows/Forms/Controls/ToolStrips/ToolStripMenuItem.ToolStripMenuItemInternalLayout.cs#L117-L127)
- [`ToolStrip.ImageScalingSize` propagation](https://github.com/dotnet/winforms/blob/f724c2277a0695ca71d1816575636afc802d73b9/src/System.Windows.Forms/System/Windows/Forms/Controls/ToolStrips/ToolStrip.cs#L920-L935)
Open API questions:
1. Should `Symbol` live on `ToolStripItem` or a narrower set of derived types?
2. Should accessibility metadata remain mutable directly on `ISymbol`?
3. How should built-in rendering discover renderers for application-defined symbol implementations?
4. Should concrete symbol types be provided by WinForms, or only the abstraction and ToolStrip integration?
5. Are the proposed zero/unconstrained size semantics consistent with existing WinForms preferred-size conventions?
# API Usage
```csharp
ISymbol addSymbol = GetAddSymbol();
var addButton = new ToolStripButton
{
DisplayStyle = ToolStripItemDisplayStyle.ImageAndText,
Text = "Add",
Symbol = addSymbol,
AccessibleName = "Add customer",
};
var menuItem = new ToolStripMenuItem
{
Text = "Add customer",
Symbol = addSymbol,
};
```
The same semantic asset can be reused in multiple contexts while each host can provide a more specific accessible name.
# Alternative Designs
- Keep `Image` as the only surface and require pre-rasterization. This loses semantic metadata and pushes DPI/theme/cache policy to every caller.
- Add `Draw(Graphics, ...)` to `ISymbol`. This permanently binds the abstraction to GDI+.
- Add SVG-specific APIs directly to ToolStrip. This makes one source format part of the host abstraction and inhibits font/procedural/future symbol sources.
- Make `Image` and `Symbol` destructively clear each other. This is simple but loses the caller's image when temporarily switching to a symbol.
# Risks
- Renderer discovery must be defined so a valid `ISymbol` never becomes a silent blank asset.
- Cache identity must include size, DPI, foreground/current color, theme, high contrast, and source content changes.
- Designer serialization, reset behavior, resource ownership, and preview rendering need an explicit design.
- Accessibility fallback must not promote stale symbol metadata into an item-level override when symbols change.
- The `Image`/`Symbol` precedence rule must preserve existing item layout and serialization predictably.
# Will this feature affect UI controls?
Yes. ToolStrip-based controls and image-bearing items would understand `Symbol` alongside `Image`, including `ToolStrip`, `MenuStrip`, `StatusStrip`, `ContextMenuStrip`, and dropdowns.
The implementation/test matrix should cover:
- symbol-only and mixed `Image`/`Symbol` items;
- symbol swap/clear and designer round-tripping;
- accessibility fallback and item-level overrides;
- 100%, 150%, 200%, and per-monitor DPI changes;
- light mode, dark mode, and high contrast;
- ToolStripButton, ToolStripMenuItem, dropdown items, status items, and custom derivatives;
- cache invalidation, ownership, disposal, and application-defined symbols.
Companion layout proposal: dotnet/winforms#14922.
Contributor guide
Research direction
Start with ToolStripItem.cs, ToolStripMenuItem.ToolStripMenuItemInternalLayout.cs, and ToolStrip.cs at the linked image-sizing and propagation paths. Review companion issue #14922, then resolve the open API, renderer, accessibility, serialization, and sizing questions before defining the implementation and test matrix. Done means an agreed design that covers symbol/image coexistence, accessibility, DPI and theme changes, supported item types, and application-defined symbols.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- desktop
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100