Code Behind
Window and UserControl files also have an associated code-behind file which usually has the extension .xaml.cs
or .axaml.cs
and may be displayed collapsed under the XAML file in your editor. Below you can see a MainWindow.xaml
file along with its markdown file MainWindow.xaml.cs
in Visual Studio:
The code-behind file by default defines a .NET class with the same name as your XAML file, e.g.
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace AvaloniaApplication1
{
public class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
#if DEBUG
AttachDevTools();
#endif
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}
Note that this class definition corresponds closely to the XAML file:
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="AvaloniaApplication1.MainWindow">
</Window>
- The base class,
Window
is the root element of the XAML file - The
x:Class
attribute references the fully-qualified name of the class defined in code-behind
If you make any changes to the base class, namespace, or name of the class, make sure to update both the code-behind and the XAML to ensure they match.
In addition, the class contains two more things of interest:
- It enables DevTools in debug mode
- It defines an
InitializeComponent
method which is used to load the XAML at runtime
Locating Controls
One of the main uses of the code-behind file is to manipulate controls using C# code. To do this you'll usually first want to get a reference to a named control. This can be done using the FindControl<T>
method:
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="AvaloniaApplication4.MainWindow">
<Button Name="myButton">Hello World</Button>
</Window>
public class MainWindow : Window
{
private Button myButton;
public MainWindow()
{
InitializeComponent();
#if DEBUG
AttachDevTools();
#endif
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
myButton = this.FindControl<Button>("myButton");
}
}
FindControl
must be called after AvaloniaXamlLoader.Load
has run because it's not until this point that the control will have been created.
The good news this step is not necessary if you're using Avalonia.NameGenerator package (added to the Avalonia templates by default), because it provides a code-generation step which creates this code for you.
In such case the code-behind class can be simplified to:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
Note the class is now declared as partial
. That's because all the boilerplate code is now auto-generated by the Avalonia.NameGenerator at the second partial class which is not visible in the project.
For the given XAML, it will look like follows:
// <auto-generated />
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace AvaloniaApplication1
{
partial class MainWindow
{
internal global::Avalonia.Controls.Button myButton;
/// <summary>
/// Wires up the controls and optionally loads XAML markup and attaches dev tools (if Avalonia.Diagnostics package is referenced).
/// </summary>
/// <param name="loadXaml">Should the XAML be loaded into the component.</param>
/// <param name="attachDevTools">Should the dev tools be attached.</param>
public void InitializeComponent(bool loadXaml = true, bool attachDevTools = true)
{
if (loadXaml)
{
AvaloniaXamlLoader.Load(this);
}
#if DEBUG
if (attachDevTools)
{
this.AttachDevTools();
}
#endif
myButton = this.FindControl<global::Avalonia.Controls.Button>("myButton");
}
}
}
The auto-generated InitializeComponent
has arguments to optionally call the AvaloniaXamlLoader.Load(this)
and AttachDevTools
, so you don't need to call them yourself from your code-behind class anymore.
Never keep a method named InitializeComponent
in your code-behind view class if you are using the generator with default settings. Read more at the Avalonia.NameGenerator documentation.
For the rest of the documentation, we'll assume you're either using Avalonia templates or added the Avalonia.NameGenerator package to your project manually.
Handling Events
Another common use for the code-behind file is to define event handlers. Event handlers are defined as methods in the code-behind and referenced from XAML. For example to add a handler for a button click:
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="AvaloniaApplication4.MainWindow">
<Button Click="MyButton_Click">Hello World</Button>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public void MyButton_Click(object sender, RoutedEventArgs e)
{
// Handle click here.
}
}