MAUI C# Markup

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
Read More →

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
See Examples →

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
Explore Advanced Topics →

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
Learn Best Practices →

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);
}