Icons & BeepImage
One control — BeepImage — resolves four icon source formats
automatically. Any control with a string icon DP (a leading/trailing icon slot, a list row's
icon) runs the same pipeline, so you set an icon by name and nothing else.
TheTechIdea.Beep.WPF.Controls.BeepImage
(derives ContentControl) ·
Icon catalog: Icons/SvgsUIcons.cs over the embedded SVGs in
GFX/Icons/uiicons/.
On this page
The four source formats
You point BeepImage (or any icon DP) at a string. The pipeline detects the format
from the string content — no flag, no per-format API. Embedded resource first, then
.svg extension, else a bitmap.
| Format | Example | Use case |
|---|---|---|
| Embedded SVG by name | fi-tr-floppy-disk |
The common case. Resolved via Icons/SvgsUIcons.cs against the embedded
SVGs in GFX/Icons/uiicons/. Same names as the WinForms library — no
path, no extension. |
| Pack URI | pack://application:,,,/MyApp;component/Icons/open.svg |
Icons shipped inside the consumer app's own assembly. |
| File path | C:/icons/cog.svg, ./logo.png |
Dev-time quick pointing at a file on disk. |
| Inline path geometry | M12 21.35l-1.45-1.32C5.4 15.36... |
A raw path-geometry string (starts with M/m/L/…).
No file — a pure vector primitive, recolored via Foreground. |
| Bitmap fallback | ./logo.png, photo.jpg |
Any non-.svg extension is loaded as a BitmapImage. |
The detection order (from BeepImage.LoadImageFromPath):
if (IsEmbeddedResource(path)) { LoadImageFromEmbeddedResource(path); return; }
_isSvg = path.EndsWith(".svg", StringComparison.OrdinalIgnoreCase);
if (_isSvg) LoadSvgImage(path);
else LoadBitmapImage(path);
Setting an icon by name is the whole API — no pipeline to wire on the consumer side:
<beep:BeepImage ImagePath="fi-tr-floppy-disk" Width="20" Height="20"/>
<!-- pack URI -->
<beep:BeepImage ImagePath="pack://application:,,,/MyApp;component/Icons/open.svg"/>
<!-- file path -->
<beep:BeepImage ImagePath="C:/icons/cog.svg"/>
<!-- inline path geometry -->
<beep:BeepImage ImagePath="M12 2 L2 22 L22 22 Z"/>
Empty string = no icon
The default and the "no icon" value is the empty string "". Templates bind an icon
slot's visibility through StringToVisibilityConverter, which returns
Collapsed for null/empty and Visible for any non-empty string. That
is the WPF-idiomatic way to conditionally show a chrome slot — the slot simply collapses when
no icon is set, leaving no gap.
<beep:BeepImage Grid.Column="0"
ImagePath="{TemplateBinding LeadingIcon}"
Visibility="{Binding LeadingIcon,
RelativeSource={RelativeSource TemplatedParent},
Converter={StaticResource StringToVisibility}}"/>
""
and let the converter collapse the slot. Setting a non-empty name is the only thing that lights
it up.
Foreground recolors SVGs
SVG content (embedded, file, pack URI, or inline path geometry) is recolored by the
Foreground brush — applied automatically when the image renders. Because that
brush comes from the active skin's tokens, icons re-tint when the theme
swaps, in step with the surrounding chrome. BeepImage exposes
Foreground plus Stroke/Fill/Background brush
DPs for finer control, and its own ImagePath, ImageSource,
Stretch and IsStillImage properties.
<!-- Icon follows the skin's OnSurface tone via a chrome token -->
<beep:BeepImage ImagePath="fi-tr-search"
Foreground="{DynamicResource BeepChrome.IconForeground}"
Width="18" Height="18"/>
Because the recolor is driven by Foreground, a single embedded SVG serves every
skin — there is no light/dark variant of an icon asset; the brush changes, not the file.
Any string icon DP uses this pipeline
The icon pipeline is not exclusive to BeepImage. Every control that exposes a
string icon DP feeds it through the same resolver — its template hosts a
BeepImage in the icon slot and binds the DP to ImagePath. So the same
four formats, the same empty-string rule, and the same Foreground recolor apply
everywhere.
| Host | String icon DP(s) |
|---|---|
IBeepIconHost (implemented by many inputs/buttons) | LeadingIcon, TrailingIcon (+ IconSize) |
BeepListItem (the rich list row) | LeadingIcon, TrailingIcon, ActionIcon |
| Buttons / text inputs / search boxes | LeadingIcon / TrailingIcon |
Set the icon by name — the host does the rest:
<beep:BeepTextBox LeadingIcon="fi-tr-search"/>
<beep:BeepButton Text="Save" LeadingIcon="fi-tr-floppy-disk"/>
<beep:BeepListItem PrimaryText="Documents"
LeadingIcon="fi-tr-folder"
TrailingIcon="fi-tr-angle-right"/>
BeepImage slots are grid columns inside the themed
RootBorder (leading | content | trailing), not siblings of it — otherwise they
render free-floating with no chrome. See
Chrome, Skins & Themes for the token system that
paints that border.
Gotchas
- The icon name must exist. Every embedded-SVG name must resolve to a real
file in
GFX/Icons/uiicons/. A typo returns silently — the image just doesn't render — and, when theBeepImageis composed inside a control template first instantiated at app start, a missing resource can surface as a runtimeXamlParseExceptionon first init. Confirm a name exists before referencing it (e.g.ls GFX/Icons/uiicons/ | grep -i <name>). - Some plausible names don't exist.
fi-tr-circle-exclamationandfi-tr-circle-infoare not in the catalog. Safe alternatives that are:fi-tr-alarm-exclamation,fi-tr-info,fi-tr-warning. - Prefer names over paths in shipped UI. Embedded names travel with the library and re-tint with the theme; a file path is a dev-time convenience that won't exist on another machine.