Avalonia UI 入門教程:從零開始學習
1. 什麼是 Avalonia UI?
Avalonia UI 是一個開源的跨平台 UI 框架,允許開發者使用 C# 和 XAML 創建美觀且響應迅速的桌面應用程式。它支援 Windows、macOS、Linux (Xorg 和 Wayland)、iOS、Android,甚至 WebAssembly,這意味著您可以使用一套程式碼庫覆蓋所有主流平台。Avalonia 的設計靈感來源於 WPF (Windows Presentation Foundation),對於有 WPF 或 UWP 開發經驗的開發者來說會非常熟悉。
核心優勢:
* 跨平台: 一套程式碼,多平台運行。
* 靈活的 UI 設計: 透過 XAML 實現強大的介面描述和樣式設定。
* MVVM 支援: 易於整合 Model-View-ViewModel (MVVM) 設計模式,提高程式碼可維護性。
* 活躍的社群: 作為開源專案,擁有積極的開發者社群和不斷更新的功能。
2. 環境準備 (Prerequisites)
在開始編寫您的第一個 Avalonia 應用程式之前,您需要準備以下開發環境:
-
.NET SDK: 推薦安裝 .NET 8 SDK 或更高版本。您可以從 Microsoft 官方網站 下載。
- 檢查安裝: 打開終端或命令提示字元,輸入
dotnet --version,確保顯示的版本是 8.x.x 或更高。
- 檢查安裝: 打開終端或命令提示字元,輸入
-
IDE (整合開發環境):
- Visual Studio (Windows/macOS): 推薦使用 Visual Studio 2022 或更高版本,並確保安裝了「.NET 桌面開發」工作負載。
- Visual Studio Code (跨平台): 如果您偏好輕量級編輯器,可以使用 VS Code,並安裝 C# 擴充功能。
- JetBrains Rider (跨平台): 一款功能強大的 .NET IDE,也非常適合 Avalonia 開發。
-
Avalonia 專案模板: 透過 .NET CLI 安裝 Avalonia 專案模板,這將幫助您快速建立新專案。
打開您的終端或命令提示字元,執行以下命令:bash
dotnet new install Avalonia.Templates- 檢查安裝: 執行
dotnet new list avalonia,您應該能看到 Avalonia 相關的專案模板清單。
- 檢查安裝: 執行
接下來,我們將開始創建您的第一個 Avalonia 專案。### 3. 建立您的第一個 Avalonia 專案 (Project Setup)
準備好環境後,我們就可以創建一個新的 Avalonia 應用程式專案了。
步驟 1: 建立專案資料夾
首先,創建一個您想存放專案的資料夾。例如,在您的桌面上創建一個名為 AvaloniaGettingStarted 的資料夾。
bash
mkdir AvaloniaGettingStarted
cd AvaloniaGettingStarted
步驟 2: 使用模板建立專案
在終端或命令提示字元中,導航到您剛才創建的資料夾,然後執行以下命令來創建一個新的 Avalonia MVVM 應用程式:
bash
dotnet new avalonia.mvvm -o MyAvaloniaApp
avalonia.mvvm:這是我們之前安裝的 Avalonia 專案模板之一,它會創建一個基於 MVVM 設計模式的專案結構。-o MyAvaloniaApp:指定了輸出資料夾名稱為MyAvaloniaApp。專案檔和程式碼將會在這個資料夾中生成。
步驟 3: 專案結構概覽
進入新創建的 MyAvaloniaApp 資料夾 (cd MyAvaloniaApp),然後打開您偏好的 IDE (例如 Visual Studio 或 VS Code)。您會看到類似以下的專案結構:
MyAvaloniaApp/
├── App.axaml // 應用程式的 XAML 定義,包含全局資源和樣式
├── App.axaml.cs // App.axaml 的後端程式碼 (Code-behind)
├── Program.cs // 應用程式的進入點
├── ViewLocator.cs // MVVM 中的視圖定位器
├── Views/
│ └── MainView.axaml // 主視窗的 UI 定義
│ └── MainView.axaml.cs // MainView.axaml 的後端程式碼
├── ViewModels/
│ └── MainViewModel.cs // 主視窗的 ViewModel
│ └── ViewModelBase.cs // 所有 ViewModels 的基類
└── MyAvaloniaApp.csproj // 專案檔
重要檔案說明:
Program.cs: 這是應用程式的啟動檔案,包含了Main方法,負責初始化 Avalonia UI 框架並啟動應用程式。App.axaml/App.axaml.cs: 定義了應用程式級別的資源、樣式和應用程式生命週期事件。它是所有視窗的父級。Views/MainView.axaml: 這是我們應用程式主視窗的 XAML 定義。您將在這裡設計 UI。ViewModels/MainViewModel.cs: 這是MainView的 ViewModel,負責處理業務邏輯和資料,並透過資料綁定與MainView互動。
現在,我們來看看如何理解 XAML 語法,以及它如何定義我們的應用程式介面。### 4. XAML 基礎 (XAML Basics)
XAML (Extensible Application Markup Language) 是一種基於 XML 的聲明式語言,用於定義應用程式的使用者介面。在 Avalonia 中,您使用 XAML 來描述 UI 元素的結構、外觀和行為。
打開 Views/MainView.axaml 檔案,您會看到類似以下的內容:
“`xml
“`
XAML 語法解釋:
-
根元素 (
<UserControl>或<Window>)- 每個 XAML 檔案都有一個根元素,它定義了該檔案所描述的 UI 組件類型。
- 在
MainView.axaml中,根元素是<UserControl>。對於獨立的視窗,通常是<Window>。 xmlns屬性: 定義 XML 命名空間。xmlns="https://github.com/avaloniaui":這是 Avalonia UI 元素的預設命名空間,所以您可以直接使用Button、TextBlock等而無需前綴。xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml":這是 XAML 語言服務命名空間,用於提供 XAML 語言特性,例如x:Key(用於資源字典中的鍵) 或x:Name(為元素指定一個 C# 中可訪問的名稱)。xmlns:vm="using:MyAvaloniaApp.ViewModels":這是將 C# 命名空間映射到 XAML 前綴的方式。這裡將MyAvaloniaApp.ViewModels命名空間映射為vm,這樣您就可以在 XAML 中引用您的 ViewModel。
x:DataType="vm:MainViewModel": 這是 MVVM 模式中非常重要的一點,它指定了這個UserControl的預設資料上下文類型。這使得在設計時和運行時,XAML 可以智能地與MainViewModel的屬性進行綁定。
-
元素與屬性:
- XAML 元素 (例如
<StackPanel>,<TextBlock>,<Button>) 代表了 UI 控件或佈局容器。 - 元素的屬性 (例如
Text,Margin,HorizontalAlignment,Content) 用於設定元素的各種特性。 - 屬性設定方式:
- 屬性賦值:
Text="Welcome to Avalonia!" - 內容屬性: 對於某些元素 (如
Button),其主要內容可以作為子元素直接放入,或者使用Content屬性。例如,<Button Content="Click Me!"/>等同於<Button><Button.Content>Click Me!</Button.Content></Button>(雖然第二種寫法較少見)。
- 屬性賦值:
- XAML 元素 (例如
-
嵌套與層次結構:
- UI 元素可以相互嵌套,形成一個樹狀結構。子元素會根據父元素的佈局規則進行排列。
- 例如,在
MainView.axaml中,<TextBlock>和<Button>都嵌套在<StackPanel>內部。
快速實驗:
嘗試修改 MainView.axaml 中的一些屬性,看看會發生什麼:
- 將
TextBlock的Text屬性改為"我的第一個 Avalonia 應用!"。 - 將
Button的Content屬性改為"點我一下!"。
這些修改會立即反映在您的 UI 設計中(如果您使用 Visual Studio 或 Rider,通常會有實時預覽功能)。
接下來,我們將深入了解一些基本的 Avalonia 控制項,並學習如何有效地管理它們的佈局。### 5. 基本控制項與佈局管理 (Basic Controls & Layout Management)
Avalonia UI 提供了豐富的內建控制項,用於構建互動式介面。同時,它也提供強大的佈局面板來組織這些控制項。
5.1 基本控制項 (Basic Controls)
我們將介紹幾個最常用的控制項:
-
TextBlock: 用於顯示不可編輯的文本。
xml
<TextBlock Text="這是一段文本" FontSize="16" Foreground="Blue"/>- 常用屬性:
Text(顯示的文字),FontSize(字體大小),Foreground(文字顏色),FontWeight(字體粗細)。
- 常用屬性:
-
Button: 用於執行操作的按鈕。
xml
<Button Content="提交" Width="100" Height="30"/>- 常用屬性:
Content(按鈕上顯示的內容,可以是文字、圖片或其他控件),Command(用於 MVVM 的命令綁定),Click(事件處理器)。
- 常用屬性:
-
TextBox: 允許使用者輸入和編輯文本。
xml
<TextBox Watermark="請輸入您的姓名" Width="200"/>- 常用屬性:
Text(獲取或設定文本框的內容),Watermark(提示文本),IsReadOnly(是否只讀),AcceptsReturn(是否允許換行)。
- 常用屬性:
5.2 佈局管理 (Layout Management)
佈局面板是 Avalonia 應用程式介面設計的基石。它們負責按照特定的規則排列子元素。
a. StackPanel (堆疊面板)
StackPanel 按照一個方向 (水平或垂直) 堆疊其子元素。
xml
<StackPanel Orientation="Vertical" Spacing="10" Margin="20">
<TextBlock Text="使用者資訊" FontSize="20" FontWeight="Bold"/>
<TextBox Watermark="姓名" Width="200" HorizontalAlignment="Left"/>
<TextBox Watermark="郵箱" Width="200" HorizontalAlignment="Left"/>
<Button Content="保存" Width="80" HorizontalAlignment="Left"/>
</StackPanel>
Orientation: 設定堆疊方向,Vertical(預設) 或Horizontal。Spacing: 控制子元素之間的間距 (僅限 Avalonia 11+)。Margin: 控制元素與其容器邊緣的距離。HorizontalAlignment/VerticalAlignment: 控制元素在其父容器中的對齊方式。
b. Grid (網格面板)
Grid 是一個非常強大且靈活的佈局面板,它允許您將 UI 劃分為行和列,並精確定位每個子元素。
將 MainView.axaml 的內容替換為以下 Grid 範例:
“`xml
<!-- Row 1, Column 0 -->
<TextBlock Grid.Row="1" Grid.Column="0" Text="訊息:" Margin="5" VerticalAlignment="Center"/>
<!-- Row 1, Column 1 -->
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Message}" Margin="5" AcceptsReturn="True" TextWrapping="Wrap" MinHeight="50"/>
<!-- Row 3, Column 1 (跨越所有列) -->
<Button Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Content="提交訊息" HorizontalAlignment="Right" Margin="5"/>
“`
RowDefinitions: 定義行的集合。Auto: 行高自動適應內容。*: 行高佔用所有可用空間的比例 (例如*,2*表示第一行佔 1 份,第二行佔 2 份)。像素值: 固定行高,例如50。
ColumnDefinitions: 定義列的集合,語法與RowDefinitions類似。Grid.Row/Grid.Column: 用於指定子元素所在的行和列 (基於 0)。Grid.RowSpan/Grid.ColumnSpan: 允許子元素跨越多個行或列。
在上述 Grid 範例中,我們創建了一個簡單的表單佈局,包含姓名、訊息輸入框和一個提交按鈕。
接下來,我們將學習如何讓您的應用程式響應使用者操作,例如按鈕點擊。### 6. 事件處理 (Event Handling)
使用者介面應用程式的核心之一是響應使用者的互動,例如點擊按鈕、輸入文本等。在 Avalonia 中,您可以透過事件處理器或資料綁定命令 (Command) 來實現這一點。本節我們將專注於事件處理。
步驟 1: 修改 MainView.axaml
我們將使用之前 Grid 範例中的按鈕。在 <Button> 元素上添加一個 Click 屬性,並給它一個事件處理器的名稱,例如 OnSubmitButtonClick:
“`xml
<TextBlock Grid.Row="1" Grid.Column="0" Text="訊息:" Margin="5" VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Message}" Margin="5" AcceptsReturn="True" TextWrapping="Wrap" MinHeight="50" x:Name="MessageTextBox"/> <!-- 添加 x:Name -->
<Button Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Content="提交訊息" HorizontalAlignment="Right" Margin="5"
Click="OnSubmitButtonClick"/> <!-- 添加 Click 事件 -->
``TextBox
**注意:** 我為元素添加了x:Name屬性 (NameTextBox和MessageTextBox`),這樣我們就可以在後端程式碼中直接引用這些控件來獲取它們的值。
步驟 2: 在後端程式碼中實現事件處理器
打開 Views/MainView.axaml.cs 檔案。您需要在 MainView 類中添加 OnSubmitButtonClick 方法。
“`csharp
using Avalonia.Controls;
using Avalonia.Interactivity; // 引入這個命名空間以使用 RoutedEventArgs
using Avalonia.Markup.Xaml;
namespace MyAvaloniaApp.Views
{
public partial class MainView : UserControl
{
public MainView()
{
InitializeComponent();
}
// 當按鈕被點擊時,此方法會被調用
private void OnSubmitButtonClick(object sender, RoutedEventArgs e)
{
// 獲取文本框的內容
var nameTextBox = this.FindControl<TextBox>("NameTextBox");
var messageTextBox = this.FindControl<TextBox>("MessageTextBox");
if (nameTextBox != null && messageTextBox != null)
{
string userName = nameTextBox.Text;
string message = messageTextBox.Text;
// 在這裡可以執行您的業務邏輯,例如顯示一個彈出視窗、儲存資料等
// 為了簡單起見,我們將在控制台輸出訊息
System.Console.WriteLine($"使用者名稱: {userName}, 訊息: {message}");
// 或者,您可以顯示一個簡單的訊息框
// 由於 Avalonia 尚無內建的 MessageBox,我們可以透過自定義方式實現
// 這裡暫時省略彈出框的實現,專注於控制台輸出
}
}
}
}
“`
解釋:
private void OnSubmitButtonClick(object sender, RoutedEventArgs e): 這是事件處理器的標準簽名。sender: 觸發事件的對象 (在這裡是按鈕)。e: 包含事件資料的參數。對於點擊事件,它是RoutedEventArgs類型。
this.FindControl<TextBox>("NameTextBox"): 透過x:Name屬性找到 XAML 中定義的特定控制項。System.Console.WriteLine(...): 在開發者控制台 (或 Visual Studio 的輸出視窗) 中列印訊息。
MVVM 中的 Command (命令)
雖然事件處理器在簡單的場景中非常有效,但在大型應用程式和遵循 MVVM 模式時,更推薦使用命令 (Command) 來處理 UI 互動。命令允許您將 UI 的行為邏輯從視圖 (View) 分離到 ViewModel 中,從而提高可測試性和可維護性。我們將在下一個「資料綁定」部分簡要提及命令。
現在,我們將進入 Avalonia UI 的核心概念之一:資料綁定。### 7. 資料綁定 (Data Binding)
資料綁定是 Avalonia (以及其他 MVVM 框架) 最強大的功能之一,它允許您在 UI 元素 (View) 和應用程式資料 (Model 或 ViewModel) 之間建立連接。當資料源改變時,UI 會自動更新;反之,當使用者在 UI 中改變資料時,資料源也會更新。
7.1 為什麼使用資料綁定?
- UI 與邏輯分離: 將 UI 的顯示邏輯與業務資料和行為邏輯分開,遵循 MVVM 模式。
- 減少程式碼: 無需手動編寫程式碼來更新 UI 或從 UI 中讀取資料。
- 提高可維護性: 程式碼更清晰,更易於測試和維護。
7.2 實現資料綁定:從 ViewModel 到 View
我們將把 TextBox 的 Text 屬性綁定到 MainViewModel 中的一個 C# 屬性。
步驟 1: 修改 ViewModels/MainViewModel.cs
打開 ViewModels/MainViewModel.cs 檔案。我們將添加兩個屬性 (UserName 和 Message),並為按鈕添加一個命令 (SubmitCommand)。為了讓 UI 能響應屬性值的變化,我們的 ViewModel 必須實現 INotifyPropertyChanged 介面。ViewModelBase 已經為我們處理了這個介面。
“`csharp
using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel; // 引入此命名空間以使用 ObservableProperty
using CommunityToolkit.Mvvm.Input; // 引入此命名空間以使用 RelayCommand
using System;
using System.Diagnostics; // 用於 Debug.WriteLine
namespace MyAvaloniaApp.ViewModels
{
public partial class MainViewModel : ViewModelBase
{
// 使用 ObservableProperty 生成屬性和通知更改
[ObservableProperty]
private string _greeting = “Welcome to Avalonia MVVM!”;
[ObservableProperty]
private string _userName = string.Empty; // 用於綁定姓名的屬性
[ObservableProperty]
private string _message = string.Empty; // 用於綁定訊息的屬性
// 為按鈕定義一個命令
// [RelayCommand] 會自動生成 SubmitCommand 屬性和 ExecuteSubmit 方法
[RelayCommand]
private void Submit()
{
// 在這裡執行命令的邏輯
// 現在我們可以直接訪問 _userName 和 _message 屬性
Debug.WriteLine($"使用者名稱 (來自 ViewModel): {_userName}, 訊息 (來自 ViewModel): {_message}");
// 例如,可以清空訊息或提供回饋
// Message = string.Empty; // 清空訊息框
// Greeting = $"Hello, {_userName}! Your message was: {_message}"; // 更新歡迎語
}
public MainViewModel()
{
// 這裡可以做一些初始化工作
}
}
}
“`
解釋:
CommunityToolkit.Mvvm.ComponentModel.ObservableProperty: 這是CommunityToolkit.Mvvm庫提供的一個特性,它可以自動生成INotifyPropertyChanged相關的程式碼。當私有欄位 (_userName,_message,_greeting) 改變時,它會自動通知 UI 進行更新。CommunityToolkit.Mvvm.Input.RelayCommand: 這也是CommunityToolkit.Mvvm庫的一個特性,它簡化了命令的實現。將[RelayCommand]應用於一個方法 (Submit) 後,編譯器會自動生成一個名為SubmitCommand的ICommand屬性,您可以將其綁定到 UI 上的按鈕。
步驟 2: 修改 Views/MainView.axaml
現在,我們將 TextBox 的 Text 屬性綁定到 MainViewModel 中的 UserName 和 Message 屬性,並將 Button 的 Command 綁定到 SubmitCommand。
“`xml
<!-- 綁定 UserName 屬性 -->
<TextBlock Grid.Row="1" Grid.Column="0" Text="姓名:" Margin="5" VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding UserName, Mode=TwoWay}" Margin="5"/> <!-- TwoWay 綁定 -->
<!-- 綁定 Message 屬性 -->
<TextBlock Grid.Row="2" Grid.Column="0" Text="訊息:" Margin="5" VerticalAlignment="Center"/>
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Message, Mode=TwoWay}" Margin="5" AcceptsReturn="True" TextWrapping="Wrap" MinHeight="50"/> <!-- TwoWay 綁定 -->
<!-- 綁定 SubmitCommand -->
<Button Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Content="提交訊息" HorizontalAlignment="Right" Margin="5"
Command="{Binding SubmitCommand}"/> <!-- 綁定命令 -->
“`
解釋:
Text="{Binding UserName, Mode=TwoWay}":{Binding UserName}: 告訴 Avalonia 將這個TextBox的Text屬性綁定到當前DataContext(即MainViewModel) 的UserName屬性。Mode=TwoWay: 這是雙向綁定。意味著當使用者在TextBox中輸入文本時,MainViewModel中的UserName屬性會自動更新;反之,如果UserName屬性在 ViewModel 中改變,TextBox的文本也會更新。對於TextBox的Text屬性,TwoWay通常是預設行為,但明確寫出更清晰。
Command="{Binding SubmitCommand}": 將按鈕的Command屬性綁定到MainViewModel中的SubmitCommand屬性。當按鈕被點擊時,SubmitCommand會被執行,進而調用MainViewModel中的Submit()方法。
透過這種方式,UI 和後端邏輯之間實現了鬆散耦合,大大提升了開發效率和程式碼品質。
我們已經完成了應用程式的 UI 和基本邏輯,現在是時候運行它,看看成果了!### 8. 運行與測試應用程式 (Running & Testing Your Application)
恭喜您!您已經完成了 Avalonia UI 應用程式的 UI 設計和基本邏輯綁定。現在,是時候運行它,看看您的成果了。
步驟 1: 建立並運行應用程式
打開您的終端或命令提示字元,導航到您的專案資料夾 (例如 MyAvaloniaApp),然後執行以下命令:
bash
dotnet run
這個命令會編譯您的專案 (如果它還沒有被編譯過),然後啟動應用程式。
步驟 2: 觀察結果
- 應用程式視窗: 您應該會看到一個新的桌面應用程式視窗彈出,顯示您在
MainView.axaml中設計的 UI。 - 互動測試:
- 在「姓名」和「訊息」文本框中輸入一些文字。
- 點擊「提交訊息」按鈕。
- 控制台輸出: 由於我們在
MainViewModel的Submit()命令中使用了Debug.WriteLine,當您點擊按鈕時,您應該能在運行dotnet run的終端視窗中看到輸出訊息,類似於:
使用者名稱 (來自 ViewModel): [您輸入的姓名], 訊息 (來自 ViewModel): [您輸入的訊息]
這表明您的 UI 成功地與 ViewModel 進行了雙向資料綁定,並且按鈕的命令也正確執行了。
排除錯誤 (Troubleshooting)
- 編譯錯誤: 如果
dotnet run失敗並顯示編譯錯誤,請仔細檢查您的 XAML 和 C# 程式碼,確保沒有拼寫錯誤、語法錯誤或遺漏的命名空間引用。 - 應用程式未啟動: 確保您的 .NET SDK 已正確安裝。
- UI 未更新: 檢查您的資料綁定路徑是否正確,以及 ViewModel 中的屬性是否有正確地通知 UI (透過
[ObservableProperty]或手動實現INotifyPropertyChanged)。
總結
本教程帶領您從零開始,了解了 Avalonia UI 的基本概念和開發流程:
- 環境準備: 安裝 .NET SDK 和 Avalonia 模板。
- 專案建立: 使用
dotnet new創建新專案。 - XAML 語法: 學習如何使用 XAML 定義 UI。
- 基本控制項: 掌握
TextBlock,TextBox,Button的使用。 - 佈局管理: 利用
StackPanel和Grid組織 UI 元素。 - 事件處理: 了解如何響應使用者操作。
- 資料綁定與 MVVM: 學習如何連接 UI 與後端資料,實現 MVVM 模式。
這只是 Avalonia UI 世界的冰山一角。接下來,您可以探索更多進階主題,例如:
- 樣式與模板: 自定義控制項的外觀。
- 使用者控制項: 創建可重用的 UI 組件。
- 服務定位器與依賴注入: 管理應用程式的依賴。
- 導航: 在多個視圖之間切換。
- 自定義繪製: 實現獨特的圖形效果。
希望這個教程能為您的 Avalonia UI 開發之旅奠定堅實的基礎!