avalonia docs

Avalonia

Welcome to Avalonia! Avalonia is a cross platform XAML Framework for .NET Framework, .NET Core and Mono.

Avalonia is shipped as .NET standard 2.0 NuGet packages and a set of templates for Visual Studio and .NET core. We also have a visual designer for Visual Studio.

This page is designed as a whirlwind tour of Avalonia. There are plenty of links throughout to more detailed documentation on each area, or you can navigate using the sections on the left.

If you're familiar with WPF or UWP then you should feel right at home with Avalonia. Although Avalonia is not API compatible with either of these frameworks (and so controls can't be used without porting), there's a lot of similarity. If you're a WPF user we have a page which describes the main differences between WPF and Avalonia.

Programming with Avalonia

Avalonia lets you develop an appliction using the XAML markup language and C# (or another .NET language) for code. You generally use XAML markup to implement the appearance of an application while using code to implement its behavior.

Markup

XAML is an XML-based markup language that implements an application's appearance declaratively. You typically use it to create windows and user controls, and to fill them with controls, shapes, and graphics.

The following example uses XAML to implement the appearance of a window that contains a single button:

XAML

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="AvaloniaApplication1.MainWindow"
        Title="Window with Button"
        Width="250" Height="100">
  
  <!-- Add button to window -->
  <Button Name="button">Click Me!</Button>

</Window>

Specifically, this XAML defines a window and a button by using the Window and Button elements, respectively. Each element is configured with attributes, such as the Window element's Title attribute to specify the window's title-bar text. At run time, Avalonia converts the elements and attributes that are defined in markup to instances of Avalonia classes. For example, the Window element is converted to an instance of the Window class whose Title property is the value of the Title attribute.

The following images show the user interface that is defined by the XAML in the previous example running on Windows:

Since XAML is XML-based, the UI that you compose with it is assembled in a hierarchy of nested elements known as an element tree. The element tree provides a logical and intuitive way to create and manage UIs.

Application window

Code-behind

The main behavior of an application is to implement the functionality that responds to user interactions, including handling events (for example, clicking a menu, tool bar, or button) and calling business logic and data access logic in response. In Avalonia, this behavior can be implemented in code that is associated with markup. This type of code is known as code-behind. The following example shows the updated markup from the previous example and the code-behind:

XAML

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="AvaloniaApplication1.MainWindow"
        Title="Window with Button"
        Width="250" Height="100">
  
  <!-- Add button to window -->
  <Button Name="button" Click="button_Click">Click Me!</Button>

</Window>

C#

using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;

namespace AvaloniaApplication1
{
    public class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        public void button_Click(object sender, RoutedEventArgs e)
        {
            // Change button text when button is clicked.
            var button = (Button)sender;
            button.Content = "Hello, Avalonia!";
        }

        private void InitializeComponent()
        {
            AvaloniaXamlLoader.Load(this);
        }
    }
}

In this example, the code-behind implements a class that derives from the Window class. The x:Class attribute is used to associate the markup with the code-behind class. InitializeComponent is called from the code-behind class's constructor to merge the UI that is defined in markup with the code-behind class. The combination of x:Class and InitializeComponent ensure that your implementation is correctly initialized whenever it is created. The code-behind class also implements an event handler for the button's Click event. When the button is clicked, the event handler changes the text of the button by setting a property on the Button control.

The Model-View-ViewModel Pattern

As well as writing code in code-behind, Avalonia supports using the Model-View-ViewModel pattern (or MVVM). MVVM is a common way to structure UI applications that separates view logic from application logic in a way that allows your applications to become unit-testable.

MVVM relies upon Avalonia's binding capabilities to separate your application into a View layer which displays standard Avalonia windows and controls, and a ViewModel layer which defines the functionality of the application independently of Avalonia itself. The following example shows the code from the previous example implemented using the MVVM pattern:

XAML

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="AvaloniaApplication1.MainWindow"
        Title="Window with Button"
        Width="250" Height="100">

  <!-- Add button to window -->
  <Button Content="{Binding ButtonText}" Command="{Binding ButtonClicked}"/>

</Window>

C#

using System.ComponentModel;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;

namespace AvaloniaApplication1
{
    public class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainWindowViewModel();
        }

        private void InitializeComponent()
        {
            AvaloniaXamlLoader.Load(this);
        }
    }

    public class MainWindowViewModel : INotifyPropertyChanged
    {
        string buttonText = "Click Me!";

        public string ButtonText
        {
            get => buttonText;
            set 
            {
                buttonText = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonText)));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void ButtonClicked() => ButtonText = "Hello, Avalonia!";
    }
}

In this example, the code-behind assigns the Window's DataContext property to an instance of MainWindowViewModel. The XAML then uses an Avalonia {Binding} to bind the Button's Content property to the ButtonText property on the MainWindowViewModel. It also binds the Button's Command property to the ButtonClicked method on the MainWindowViewModel.

When the Button is clicked it invokes its Command, causing the bound MainWindowViewModel.ButtonClicked method to be called. This method then sets the ButtonText property which raises the INotifyPropertyChanged.PropertyChanged event, causing the Button to re-read its bound value and update the UI.

Controls

Avalonia provides many core controls. Here are some of the most common:

Input and Commands

Controls most often detect and respond to user input. The Avalonia input system uses both direct and routed events to support text input, focus management, and mouse positioning.

Applications often have complex input requirements. Avalonia provides a command system that separates user-input actions from the code that responds to those actions.

Layout

When you create a user interface, you arrange your controls by location and size to form a layout. A key requirement of any layout is to adapt to changes in window size and display settings. Rather than forcing you to write the code to adapt a layout in these circumstances, Avalonia provides a first-class, extensible layout system for you.

The cornerstone of the layout system is relative positioning, which increases the ability to adapt to changing window and display conditions. In addition, the layout system manages the negotiation between controls to determine the layout. The negotiation is a two-step process: first, a control tells its parent what location and size it requires; second, the parent tells the control what space it can have.

The layout system is exposed to child controls through base Avalonia classes. For common layouts such as grids, stacking, and docking, Avalonia includes several layout controls:

You can also create your own layouts by deriving from the Panel class.

Data Binding

Avalonia includes comprehensive support for binding between controls and to aribtrary .NET objects. Data binding can be set up in XAML or in code and supports:

The following example shows a TextBlock when an associated TextBox is disabled, by using a binding:

XAML

<StackPanel>
    <TextBox Name="input" IsEnabled="False"/>
    <TextBlock IsVisible="{Binding !#input.IsEnabled}">Sorry, no can do!</TextBlock>
</StackPanel>

In this example, a binding is set up to the IsEnabled property of the input control using #input.IsEnabled and the value of that binding is negated and fed into the TextBlock.IsVisible property.

Styling

Styles in Avalonia are used to share property settings between controls. The Avalonia styling system can be thought of as a mix of CSS styling and WPF/UWP styling. At its most basic, a style consists of a selector and a collection of setters.

The following style selects any TextBlock in the Window with a h1 style class and sets its font size to 24 point and font weight to bold:

XAML

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Window.Styles>
        <Style Selector="TextBlock.h1">
            <Setter Property="FontSize" Value="24"/>
            <Setter Property="FontWeight" Value="Bold"/>
        </Style>
    </Window.Styles>

    <TextBlock Classes="h1">I'm a Heading!</TextBlock>
</Window>

Graphics

Avalonia introduces an extensive, scalable, and flexible set of graphics features that have the following benefits:

2D Shapes and Geometries

Avalonia provides a library of common vector-drawn 2D shapes such as Ellipse, Line, Path, Polygon and Rectangle.

XAML

<Canvas Background="Yellow" Width="300" Height="400">
    <Rectangle Fill="Blue" Width="63" Height="41" Canvas.Left="40" Canvas.Top="31">
    <Rectangle.OpacityMask>
        <LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
        <LinearGradientBrush.GradientStops>
            <GradientStop Offset="0" Color="Black"/>
            <GradientStop Offset="1" Color="Transparent"/>
        </LinearGradientBrush.GradientStops>
        </LinearGradientBrush>
    </Rectangle.OpacityMask>     
    </Rectangle>
    <Ellipse Fill="Green" Width="58" Height="58" Canvas.Left="88" Canvas.Top="100"/>
    <Path Fill="Orange" Data="M 0,0 c 0,0 50,0 50,-50 c 0,0 50,0 50,50 h -50 v 50 l -50,-50 Z" Canvas.Left="30" Canvas.Top="250"/>
    <Path Fill="OrangeRed" Canvas.Left="180" Canvas.Top="250">
    <Path.Data>
        <PathGeometry>
        <PathFigure StartPoint="0,0" IsClosed="True">
            <QuadraticBezierSegment Point1="50,0" Point2="50,-50" />
            <QuadraticBezierSegment Point1="100,-50" Point2="100,0" />
            <LineSegment Point="50,0" />
            <LineSegment Point="50,50" />
        </PathFigure>
        </PathGeometry>
    </Path.Data>
    </Path>
    <Line StartPoint="120,185" EndPoint="30,115" Stroke="Red" StrokeThickness="2"/>
    <Polygon Points="75,0 120,120 0,45 150,45 30,120" Stroke="DarkBlue" StrokeThickness="1" Fill="Violet" Canvas.Left="150" Canvas.Top="31"/>
    <Polyline Points="0,0 65,0 78,-26 91,39 104,-39 117,13 130,0 195,0" Stroke="Brown" Canvas.Left="30" Canvas.Top="350"/>
</Canvas>

Drawing shapes

Animation

Avalonia's animation support lets you make controls grow, shake, spin, and fade, to create interesting page transitions, and more. Avalonia uses a CSS-like animation system which supports property transitions and keyframe animations.