Styles and themes

Reuse typed property sets and apply implicit styles across an application.

Style<T> is a named block of setters for one view type:

static readonly Style<Border> CardStyle = new(card =>
{
    card.Padding = 16;
    card.Background = Colors.SecondaryGroupedBackground;
    card.CornerRadius = 14;
    card.Stroke = Colors.Separator;
    card.StrokeThickness = 0.5;
});

Assign it through View.Style. Put the style first in an object initializer because assignments run in source order:

new Border
{
    Style = CardStyle,
    CornerRadius = 20,
    Child = content
};

The later local CornerRadius overrides the style. Assigning Style last would apply all its setters over earlier values.

Style inheritance

A style can build on another compatible style:

static readonly Style<Border> ElevatedCardStyle = new(
    CardStyle,
    card => card.Shadow = new Shadow(0.14, 14, 6));

The base style runs first, then the derived setters. The base target must be assignable from the derived target; a style for an unrelated control cannot be applied.

Implicit themes

Register application-wide styles during startup:

.UseTheme(theme => theme
    .Style(new Style<Label>(label =>
        label.TextColor = Colors.Label))
    .Style(CardStyle))

When a view is constructed, the theme applies matching styles from base types to the concrete type. A Style<View> can establish shared defaults, then a Style<Button> or Style<Border> can refine them.

Explicit styles and local initializer values run after the constructor, so they override the implicit theme. A theme is frozen when the app begins using it and cannot be changed later. Use bindable colors, appearance changes, or explicit state updates for runtime theming rather than trying to register another theme.

Styles execute normal C# setters. They do not create a separate property-value layer, and changing the Style<T> object later does not revisit existing views.