Uno Platform C# Markup
Declarative, fluent-style C# syntax for building Uno Platform UIs. Same underlying object model as XAML with compile-time validation, IntelliSense, and refactoring support.
Setup
Select C# Markup in the project template:
dotnet new unoapp -markup csharp
Add CSharpMarkup to UnoFeatures for existing projects:
<UnoFeatures>
CSharpMarkup;
Material;
Toolkit;
</UnoFeatures>
Pages use .cs files instead of .xaml + .xaml.cs pairs.
Core Patterns
Creating Controls and Setting Properties
Fluent API chains property setters. Type conversion is automatic for common types (Thickness, Brush, Color, CornerRadius, FontFamily).
new TextBlock()
.Margin(12) // auto-converts int to Thickness
.TextAlignment(TextAlignment.Center) // strongly typed enum
.Text("Hello Uno Platform!")
Children and Content
new StackPanel()
.VerticalAlignment(VerticalAlignment.Center)
.HorizontalAlignment(HorizontalAlignment.Center)
.Children(
new TextBlock().Text("First"),
new TextBlock().Text("Second"),
new Button().Content("Click me")
)
DataContext and Binding
Use expression trees for strongly-typed binding. The vm parameter is a placeholder, not a live reference.
public sealed partial class MainPage : Page
{
public MainPage()
{
this.DataContext(new MainViewModel(), (page, vm) => page
.Background(ThemeResource.Get<Brush>("ApplicationPageBackgroundThemeBrush"))
.Content(
new StackPanel()
.VerticalAlignment(VerticalAlignment.Center)
.Children(
new TextBlock()
.Text(() => vm.Count, count => $"Counter: {count}"),
new TextBox()
.Text(x => x.Bind(() => vm.Step).TwoWay()),
new Button()
.Command(() => vm.IncrementCommand)
.Content("Increment")
)
)
);
}
}
Binding modes:
- Default (OneWay):
() => vm.Property - TwoWay:
.Text(x => x.Bind(() => vm.Property).TwoWay()) - OneTime:
.Text(x => x.Bind(() => vm.Property).OneTime())
Without ViewModel instance (type-only):
this.DataContext<MainViewModel>((page, vm) => page
.Content(...)
);
Resources
Access theme and static resources with strongly-typed API:
// Theme resource
this.Background(ThemeResource.Get<Brush>("ApplicationPageBackgroundThemeBrush"));
// Static resource
new TextBlock()
.Style(StaticResource.Get<Style>("TitleLarge"));
Styles
new TextBlock()
.Style(new Style<TextBlock>()
.Setters(s => s
.Foreground(ThemeResource.Get<Brush>("OnSurfaceBrush"))
.FontSize(24)
)
)
Templates
new ListView()
.ItemsSource(() => vm.Items)
.ItemTemplate<MyItem>(item =>
new StackPanel()
.Orientation(Orientation.Horizontal)
.Children(
new TextBlock().Text(() => item.Name),
new TextBlock().Text(() => item.Description)
)
)
Uno Toolkit in C# Markup
Toolkit controls work with the same fluent API:
using Uno.Toolkit.UI;
new AutoLayout()
.Spacing(16)
.Padding(24)
.PrimaryAxisAlignment(AutoLayoutAlignment.Center)
.Children(
new NavigationBar().Content("Page Title"),
new SafeArea()
.Insets(SafeArea.InsetMask.Top | SafeArea.InsetMask.Bottom)
.Child(
new TextBlock().Text("Safe content")
)
)
ResponsiveExtension in C# Markup
Responsive values require XAML-style markup extensions. In C# Markup, use adaptive logic or VisualStateManager instead:
// Use VisualStateManager for responsive layouts in C# Markup
new Grid()
.VisualStateManager(vsm => vsm
.Group(g => g.Name("WidthStates")
.State(s => s.Name("Narrow")
.StateTriggers(new AdaptiveTrigger() { MinWindowWidth = 0 })
.Setters(/* narrow layout */)
)
.State(s => s.Name("Wide")
.StateTriggers(new AdaptiveTrigger() { MinWindowWidth = 800 })
.Setters(/* wide layout */)
)
)
)
MVUX with C# Markup
C# Markup pairs naturally with MVUX models. Bind directly to Feed/State properties:
this.DataContext<MainModel>((page, vm) => page
.Content(
new FeedView()
.Source(() => vm.Items)
.DataTemplate<ItemViewModel>(item =>
new TextBlock().Text(() => item.Name)
)
)
);
Common Mistakes
- Using string-based
{Binding}syntax instead of expression-tree bindings - Forgetting that
vmis a placeholder, not a live object (don't call methods on it outside binding expressions) - Setting
DataContextin code-behind AND in the fluent chain (double initialization) - Not adding
CSharpMarkupto UnoFeatures (extension methods won't be generated) - Mixing XAML and C# Markup in the same page (use one or the other per page)
Key Differences from XAML
| XAML | C# Markup |
|---|---|
{x:Bind Path} | () => vm.Path |
{Binding Path, Mode=TwoWay} | x => x.Bind(() => vm.Path).TwoWay() |
{StaticResource Key} | StaticResource.Get<T>("Key") |
{ThemeResource Key} | ThemeResource.Get<T>("Key") |
x:Uid="MyPage.Title" | Set programmatically or use attached properties |
.xaml + .xaml.cs | Single .cs file |
Limitations
- Hot Design only supports XAML markup files (not C# Markup) at this time
- XAML-only markup extensions (
{utu:Responsive}) need alternative patterns in C# Markup - Localization with
x:Uidrequires manual string loading viaResourceLoader
Detailed References
- references/01-getting-started.md - Read when creating a C# Markup project or understanding the fluent API
- references/02-binding-resources.md - Read when implementing data binding, static/theme resources, or converters
- references/03-styles-templates.md - Read when defining styles, templates, or VisualStateManager in C#
- references/04-toolkit-integration.md - Read when using Uno Toolkit controls or responsive patterns in C# Markup
