Documentation/guides/basics/code-behind.md

175 строки
5.8 KiB
Markdown

# Code-behind
[Window](https://docs.avaloniaui.net/docs/controls/window) and [UserControl](https://docs.avaloniaui.net/docs/controls/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:
![Code-behind in Visual Studio](../../.gitbook/assets/codebehind-vs.png)
The code-behind file by default defines a .NET class with the same name as your XAML file, e.g.
```csharp
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:
```markup
<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](https://docs.avaloniaui.net/docs/getting-started/developer-tools) in debug mode
* It defines an `InitializeComponent` method which is used to load the XAML at runtime
### Locating Controls <a id="locating-controls"></a>
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:
```markup
<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>
```
```csharp
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](https://github.com/AvaloniaUI/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:
```csharp
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:
```csharp
// <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](https://github.com/AvaloniaUI/Avalonia.NameGenerator#advanced-usage).
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 <a id="handling-events"></a>
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:
```markup
<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>
```
```csharp
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public void MyButton_Click(object sender, RoutedEventArgs e)
{
// Handle click here.
}
}
```