刚接触 Avalonia 的开发者,往往会在第一个月陷入一个相似的困境:项目能跑,但目录像一锅粥。ViewModel 里直接操作 UI 控件,Model 和 View 逻辑混在一起,.axaml 文件散落在项目根目录里……等到需要加一个新功能,发现改一处、错三处,心里那叫一个崩溃。
这不是能力问题,是起点没搭好的问题。
Avalonia 本身是一个设计极为克制、层次感很强的跨平台 UI 框架。它天然适配 MVVM 模式,配合 .NET 10 的新特性,能让你写出结构清晰、可跨平台编译、可长期维护的桌面应用。但前提是——你得先搞清楚它的项目骨架是什么样的,工具链该怎么配。
读完这篇文章,你将掌握:
用 dotnet new avalonia.mvvm 创建项目,模板会自动生成一套目录。大多数人看了一眼,就直接开始往里塞代码。结果是:
Views/ 里的 .axaml.cs 文件开始承担业务逻辑ViewModels/ 里直接 new Window() 弹出子窗口Models/ 要么空着,要么被当成"什么都往里放"的垃圾桶这种混乱在项目规模小的时候感觉不明显,但一旦页面超过 5 个、数据源超过 3 个,维护成本就会指数级上升。有过实际项目经历的人大概都有体感:重构一个结构混乱的 Avalonia 项目,比从头写一个还痛苦。
在结构混乱的项目中,新增一个带数据交互的页面,平均需要修改 4~6 个不相关的文件,且极易引入回归 Bug。而在结构规范的 MVVM 项目中,同样的操作只需新建 2~3 个文件,改动范围可控、可测试。
Avalonia 的绑定系统、命令系统、样式系统,全部围绕 MVVM 构建。INotifyPropertyChanged、ReactiveUI、CommunityToolkit.Mvvm 这三套响应式基础设施,在 Avalonia 里都有一流支持。选择哪套是风格问题,但把 ViewModel 和 View 分离是不可妥协的底线。
View 只负责展示,不包含任何业务判断。ViewModel 只操作数据,不引用任何 Avalonia 控件类型。Model 只描述数据结构,不知道 UI 的存在。这三条原则,是所有后续讨论的基础。
首先确保 .NET 10 SDK 已安装,然后安装 Avalonia 模板:
bash# 安装最新 Avalonia 模板(支持 .NET 10)
dotnet new install Avalonia.Templates
# 创建 MVVM 结构项目
dotnet new avalonia.mvvm -o AppMyAvalonia
# 查看所有可用模板
dotnet new list --tag Avalonia
执行完毕后,项目目录如下:
AppMyAvalonia/ ├── Assets/ # 静态资源:图标、图片、字体 ├── Models/ # 数据模型层 ├── ViewModels/ # 视图模型层 │ ├── ViewModelBase.cs # ViewModel 基类 │ └── MainWindowViewModel.cs ├── Views/ # 视图层 │ ├── MainWindow.axaml # 主窗口 XAML │ └── MainWindow.axaml.cs # 主窗口 Code-behind(尽量保持空) ├── App.axaml # 应用入口与全局资源 ├── App.axaml.cs # 应用启动逻辑 ├── Program.cs # 程序入口点 └── MyAvaloniaApp.csproj # 项目配置文件
这套结构是最小可用版本,适合 Demo 和小型工具。但在生产项目中,还需要进一步细化。
在实际项目中,我通常会在模板基础上扩展成以下结构:
MyAvaloniaApp/ ├── Assets/ │ ├── Icons/ │ ├── Fonts/ │ └── Images/ ├── Models/ │ ├── Entities/ # 领域实体(如 UserEntity.cs) │ └── DTOs/ # 数据传输对象 ├── Services/ # 业务逻辑服务层(不依赖 UI) │ ├── IUserService.cs │ └── UserService.cs ├── ViewModels/ │ ├── Base/ │ │ └── ViewModelBase.cs │ ├── MainWindowViewModel.cs │ └── Pages/ # 各页面的 ViewModel │ └── HomePageViewModel.cs ├── Views/ │ ├── MainWindow.axaml │ ├── MainWindow.axaml.cs │ └── Pages/ # 各页面 View │ └── HomePage.axaml ├── Converters/ # 值转换器 ├── Controls/ # 自定义控件 ├── App.axaml ├── App.axaml.cs └── Program.cs
这套结构的核心思想是:Services 层承接所有业务逻辑,ViewModel 只负责调用 Service 并把结果暴露给 View。这样无论是单元测试还是后续平台迁移,成本都极低。
csharp// ViewModels/Base/ViewModelBase.cs
using CommunityToolkit.Mvvm.ComponentModel;
namespace MyAvaloniaApp.ViewModels.Base;
/// <summary>
/// 所有 ViewModel 的基类,提供属性变更通知能力
/// </summary>
public abstract partial class ViewModelBase : ObservableObject
{
// ObservableObject 已实现 INotifyPropertyChanged
// 子类使用 [ObservableProperty] 特性自动生成属性
}
csharpusing CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Threading.Tasks;
namespace AppMyAvalonia.ViewModels;
public partial class MainWindowViewModel : ViewModelBase
{
// [ObservableProperty] 会自动生成 UserName 属性及通知逻辑
[ObservableProperty]
private string _userName = string.Empty;
[ObservableProperty]
private bool _isLoading;
/// <summary>
/// 异步加载命令,UI 线程安全
/// </summary>
[RelayCommand]
private async Task LoadDataAsync()
{
IsLoading = true;
try
{
// 调用 Service 层,不在 ViewModel 里写业务逻辑
await Task.Delay(500); // 模拟网络请求
UserName = "Avalonia Developer";
}
finally
{
IsLoading = false;
}
}
}
xml<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:AppMyAvalonia.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="AppMyAvalonia.Views.MainWindow"
x:DataType="vm:MainWindowViewModel"
Icon="/Assets/avalonia-logo.ico"
Title="AppMyAvalonia">
<Design.DataContext>
<!-- This only sets the DataContext for the previewer in an IDE,
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
<vm:MainWindowViewModel/>
</Design.DataContext>
<StackPanel Spacing="16" Margin="24">
<!-- 加载指示器 -->
<ProgressBar IsIndeterminate="True"
IsVisible="{Binding IsLoading}" />
<!-- 数据展示 -->
<TextBlock Text="{Binding UserName}"
FontSize="24"
FontWeight="Bold" />
<!-- 命令绑定 -->
<Button Content="加载数据"
Command="{Binding LoadDataCommand}"
IsEnabled="{Binding !IsLoading}" />
</StackPanel>
</Window>

踩坑预警: Avalonia 11+ 引入了编译时绑定(Compiled Bindings),
x:DataType是必填项,否则绑定会退化为运行时反射模式,性能下降且无法在 IDE 中获得智能提示。这是新手最容易忽略的一点。
Visual Studio 对 Avalonia 的支持依赖官方扩展,配置步骤如下:
CommunityToolkit.Mvvm NuGet 包:bashdotnet add package CommunityToolkit.Mvvm dotnet add package Avalonia dotnet add package Avalonia.Desktop dotnet add package Avalonia.Themes.Fluent
Visual Studio 的优势在于调试体验和与 Windows 生态的集成,适合以 Windows 为主要目标平台的团队。
Rider 对 Avalonia 的支持是开箱即用的,从 2020.3 版本起内置了对 .axaml 文件的一流支持,包括智能补全、实时预览、XAML 语义检查。
配置流程极简:
bash# 在 Rider 的 Terminal 中验证环境
dotnet --version # 确认 .NET 10 SDK
dotnet new list | grep avalonia # 确认模板已安装
为什么更推荐 Rider? 实际项目中,跨平台调试(在 Mac 上调试 Linux 行为)只有 Rider 能做到。而且 Rider 的 AXAML 预览刷新速度比 VS 扩展快很多,尤其在复杂样式场景下,体验差距非常明显。
.csproj 文件是整个项目的"体检报告",在 .NET 10 + Avalonia 组合下,一个标准配置如下:
xml<!-- MyAvaloniaApp.csproj -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- 目标框架:.NET 10,桌面平台 -->
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<!-- 启用 AOT 兼容的源生成器 -->
<Optimize>true</Optimize>
</PropertyGroup>
<ItemGroup>
<!-- Avalonia 核心包 -->
<PackageReference Include="Avalonia" Version="12.0.0" />
<PackageReference Include="Avalonia.Desktop" Version="12.0.0" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="12.0.0" />
<!-- MVVM 工具包(源生成器方式,零反射) -->
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.3.2" />
</ItemGroup>
</Project>
重点说明: Avalonia 12.x 已正式放弃对 .NET Framework 和 .NET Standard 2.0 的支持,最低要求 .NET 8,推荐 .NET 10。这不是随意的版本切割,而是为了使用
Span<T>、Memory<T>等现代内存 API 实现高帧率渲染——Avalonia 团队的遥测数据显示,仍在使用旧版运行时的活跃项目不足 4%,这个决策有充分的数据支撑。
第一句: Avalonia 的项目结构不是随意组织的,Models / ViewModels / Views / Services 四层分离是可维护项目的最低门槛。
第二句: 工具选择上,Windows 专属项目用 Visual Studio + 官方扩展;跨平台项目首选 JetBrains Rider,调试体验和 AXAML 支持都更完整。
第三句: x:DataType + [ObservableProperty] + [RelayCommand] 这三个组合,是 .NET 10 时代 Avalonia MVVM 开发的黄金标配,能同时兼顾性能与开发效率。
你目前在用 Avalonia 开发什么类型的项目?是桌面工具、工控界面,还是跨平台企业应用?在项目结构上有没有踩过类似的坑,或者形成了自己的最佳实践?欢迎在评论区分享你的经验。
另外,如果你的项目需要同时支持 Windows 和 Linux,在调试环境配置上遇到过哪些具体问题?这个话题值得单独展开聊聊。
对于想系统深入 Avalonia 的开发者,建议按以下路径推进:
标签: C# Avalonia .NET 10 MVVM 跨平台开发 桌面应用 开发工具
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!