Unlock Modern UI Development with C# Markup
Discover the power and elegance of building your .NET MAUI user interfaces entirely in C#, leveraging type-safe code and intuitive APIs.
Introduction to C# Markup
Learn the fundamental concepts behind C# Markup for .NET MAUI. Understand how it simplifies UI creation, reduces boilerplate, and enhances developer productivity.
- The C# Markup Philosophy
- Basic Syntax and Structure
- Benefits over XAML
Building Views with C# Markup
Dive into practical examples of constructing various UI elements, from simple labels and buttons to complex layouts and lists, all with C# code.
- Creating Pages and Views
- Using Standard Controls
- Customizing Control Properties
Advanced Techniques
Explore more sophisticated patterns and practices for leveraging C# Markup, including data binding, styling, and reusable components.
- Data Binding with C# Markup
- Styling and Theming
- Creating Reusable UI Components
- Event Handling
Performance and Best Practices
Understand how C# Markup impacts performance and learn best practices for writing efficient and maintainable UI code.
- Performance Considerations
- Code Organization
- Testing C# Markup UIs
Introduction to C# Markup
The C# Markup Philosophy
C# Markup for .NET MAUI is designed to bring the full power and expressiveness of C# directly into your UI definition. This approach offers several advantages:
- Type Safety: Catch errors at compile-time rather than runtime.
- Readability: UI code reads like application code.
- Productivity: Leverage IntelliSense, refactoring, and your existing C# knowledge.
- Maintainability: Easier to manage complex UI logic.
Basic Syntax and Structure
The core idea is to instantiate controls and configure their properties directly using C# syntax. Here's a simple example:
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Hosting;
using Microsoft.Maui.Hosting;
// ...
public class MyPage : ContentPage
{
public MyPage()
{
Content = new StackLayout
{
Children =
{
new Label { Text = "Hello, MAUI C# Markup!" }.Center(),
new Button { Text = "Click Me" }.OnClicked(async () => await DisplayAlert("Clicked", "You clicked the button!", "OK"))
}
};
}
}
Notice the fluent API extensions like .Center()
and .OnClicked()
which further enhance readability.
Benefits over XAML
While XAML is a powerful declarative language, C# Markup offers:
- No separate file for UI definitions, keeping related code together.
- Full C# capabilities within your UI, including loops, conditionals, and method calls.
- Elimination of XAML parsing overhead at runtime.
- Simplified tooling integration with existing C# development workflows.
Building Views with C# Markup
Creating Pages and Views
You can define entire pages or reusable view components using classes that inherit from MAUI's content views.
public class SimpleFormPage : ContentPage
{
public SimpleFormPage()
{
var nameEntry = new Entry { Placeholder = "Enter your name" };
var submitButton = new Button { Text = "Submit" };
Content = new StackLayout
{
Padding = new Thickness(20),
Spacing = 10,
Children =
{
new Label { Text = "Enter Your Details", FontSize = 24, FontAttributes = FontAttributes.Bold }.CenterHorizontal(),
nameEntry,
submitButton
}
};
submitButton.Clicked += (s, e) =>
{
DisplayAlert("Submission", $"Hello, {nameEntry.Text}!", "Got it");
};
}
}
Using Standard Controls
All .NET MAUI controls are available for instantiation and configuration. The C# Markup library provides convenient extension methods for common properties and events.
Examples of common controls:
Label
Button
Entry
,Editor
Image
ListView
,CollectionView
CheckBox
,Switch
Customizing Control Properties
You can set any public property of a control directly. Extension methods often provide a more concise way to set frequently used properties or complex types.
new Image { Source = "dotnet_bot.png" }
.WidthRequest(200)
.HeightRequest(200)
.Aspect(Aspect.AspectFit)
.Shadow(new Shadow { Brush = Colors.Gray, Opacity = 0.8f, Radius = 5 });
Advanced Techniques
Data Binding with C# Markup
C# Markup integrates seamlessly with .NET MAUI's data binding capabilities, allowing you to create dynamic and responsive UIs.
Binding a Label's text to a ViewModel property:
public class MyViewModel : BindableObject
{
public static readonly BindableProperty MessageProperty =
BindableProperty.Create(nameof(Message), typeof(string), typeof(MyViewModel), "Initial Message");
public string Message
{
get => (string)GetValue(MessageProperty);
set => SetValue(MessageProperty, value);
}
}
// In your Page:
public class DataBoundPage : ContentPage
{
public DataBoundPage()
{
var messageLabel = new Label();
var viewModel = new MyViewModel();
messageLabel.SetBinding(Label.TextProperty, nameof(MyViewModel.Message));
Content = new StackLayout
{
Children =
{
messageLabel,
new Button { Text = "Change Message" }.OnClicked(() => viewModel.Message = $"Updated at {DateTime.Now}")
}
};
BindingContext = viewModel;
}
}
Styling and Theming
Apply styles directly to controls or define reusable styles that can be applied across your application.
// Applying inline style
new Label("Styled Text")
.FontSize(20)
.TextColor(Colors.Purple);
// Defining a style for reuse
var primaryButtonStyle = new Style
Creating Reusable UI Components
Encapsulate common UI patterns into reusable classes for consistency and maintainability.
public class IconLabel : Grid
{
public IconLabel(string text, string iconSource)
{
this.ColumnDefinitions = Columns.Define(
(Column.Icon, Auto),
(Column.Text, Star));
Children.Add(new Image { Source = iconSource, WidthRequest = 24, HeightRequest = 24 })
.Column(Column.Icon);
Children.Add(new Label { Text = text, VerticalOptions = LayoutOptions.Center })
.Column(Column.Text)
.Paddings(left: 10);
}
enum Column { Icon, Text }
}
// Usage:
new IconLabel("User Profile", "user_icon.png");
Event Handling
Handle events using lambdas or method references for a clean and direct approach.
new Button("Show Alert")
.OnClicked(async () => await DisplayAlert("Info", "This is an alert!", "Close"));
var slider = new Slider().OnValueChanged((sender, e) =>
{
Console.WriteLine($"Slider value changed: {e.NewValue}");
});
Performance and Best Practices
Performance Considerations
When using C# Markup, be mindful of object instantiation. While generally efficient, avoid creating complex UI elements repeatedly within loops or frequently called methods if they don't change.
- Pre-instantiate complex or static components.
- Reuse UI elements where appropriate.
- Profile your application to identify performance bottlenecks.
Code Organization
Organize your C# Markup code logically:
- Create separate files for different pages and reusable components.
- Use namespaces effectively.
- Keep view logic within the view class or a dedicated ViewModel.
Testing C# Markup UIs
Testing UIs defined in C# can be more straightforward than testing XAML. You can instantiate your pages and components directly in your unit tests and assert property values or trigger events.
// Example unit test (conceptual)
[TestMethod]
public void MyPage_InitialState_Correct()
{
var page = new MyPage();
var label = page.FindControl<Label>(); // Assuming a FindControl helper method
Assert.AreEqual("Hello, MAUI C# Markup!", label.Text);
}