Avalonia.Markup.Declarative:实践指南
工作中遇到相关需求时,Avalonia.Markup.Declarative值得先读说明,因为它主要用于为 C# 中的声明式 ui 提供帮助程序。对界面与前端开发任务来说,视觉还原、交互状态和响应式细节容易遗漏往往决定它能否落地,不能只用安装成功来判断。落地前可以选一个包含多状态的真实组件完成实现,用尺寸、状态、可访问性、资源和不同视口表现判断它是否真的省事。对愿意逐状态验收界面质量的前端团队来说,这个仓库值得继续验证;只求即装即用的人则要先看维护成本。
免责声明
重要提示: 该存储库是社区驱动的,不受 avalonia 团队的正式支持,也不属于官方 Avalonia 项目的一部分 - 它只是一个概念证明,演示如何纯粹用 C# 编写标记。对于实际项目,请使用 Avalonia 支持的 XAML 方法。
Avalonia.Markup.声明式
像老板一样用 C# 编写 Avalonia UI
Avalonia.Markup.Declarative 是 Avalonia 控件上的 C# 优先创作层。当前的 API 是编译绑定优先和源生成器驱动的,其公共模式有意与 Avalonia 的 DataContext、绑定、样式和选择器模型保持一致。
使用 Avalonia.Markup.Declarative 的真实项目
https://github.com/gritsenko/pix2d - 面向独立开发人员的 Pix2d 图形编辑器
随意添加您的项目
安装
将 Avalonia.Markup.Declarative NuGet 包添加到您的项目中
项目模板
您可以使用官方模板从命令行轻松创建新项目:
dotnet new install Declarative.Avalonia.Templates
dotnet new avalonia-declarative -n MyApp
声明性组件模式(单个文件 component/SFC)
当视图及其反应状态属于同一功能时,请使用独立的声明性组件。将 CommunityToolkit.Mvvm 添加到应用程序项目,并将组件本地状态保留在嵌套的 ObservableObject 中。
using Avalonia.Data;
using CommunityToolkit.Mvvm.ComponentModel;
public class CounterComponent() : ViewBase<CounterComponent.State>(new State())
{
public sealed partial class State : ObservableObject
{
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(CounterLabel))]
public partial decimal? Counter { get; set; } = 0;
[ObservableProperty]
public partial string StatusText { get; set; } = "Hello world";
public string CounterLabel => $"Counter: {Counter}";
}
protected override object Build(State state) =>
new StackPanel()
.Children(
new TextBlock()
.Text(state, x => x.StatusText),
new TextBlock()
.Text(state, x => x.CounterLabel),
new NumericUpDown()
.Value(state, x => x.Counter, BindingMode.TwoWay),
new Button()
.Content("Increment")
.OnClick(_ => state.Counter++)
);
}
要编写构造函数注入视图,首选 ViewFactory.Create<T>()。如果您使用DI,请在AppBuilder上注册UseComponentControlFactory(...)。
MVVM 模式实现
当您想要经典的 Avalonia 或 WPF-style 视图模型时,请使用 ViewBase<TViewModel>。生成的 setter 公开编译绑定重载,因此绑定语法与本机 Avalonia 保持接近。
using Avalonia.Data;
public class MainView() : ViewBase<MainViewModel>(new MainViewModel())
{
protected override object Build(MainViewModel vm) =>
new StackPanel()
.Children(
new TextBox()
.Text(vm, x => x.Message, BindingMode.TwoWay),
new TextBlock()
.Text(vm, x => x.Message),
new Button()
.Content("Reset")
.OnClick(_ => vm.Message = string.Empty)
);
}
相同视图的等效 XAML:
<UserControl
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:MyApp.ViewModels"
x:Class="MyApp.MainView"
x:DataType="vm:MainViewModel">
<StackPanel>
<TextBox Text="{CompiledBinding Message, Mode=TwoWay}" />
<TextBlock Text="{CompiledBinding Message}" />
<Button Content="Reset"
Click="ResetClick" />
</StackPanel>
</UserControl>
如果从外部分配 DataContext,则相同的生成器还支持 DataContext-relative 编译绑定,例如 new TextBlock().Text<MainViewModel>(x => x.Message);。
生成的编译绑定 setter 还对常见原语和可为 null 的不匹配应用自动转换,因此当 Counter 为 int 时,像 new Slider().Value(vm, x => x.Counter, BindingMode.TwoWay) 这样的绑定可以工作,而当 Enabled 为 bool 时,new CheckBox().IsChecked(vm, x => x.Enabled) 可以工作。更喜欢普通成员访问,例如 x => x.Counter:像 x => (double)x.Counter 这样的数字转换强制转换既不必要(自动转换器处理它),又不受支持 — Avalonia 的表达式解析器拒绝值转换 Convert 节点。 *支持导航到派生类型成员的类型转换,例如 x => ((DerivedType)x).Property。对于有损数字 TwoWay 转换,转换回会截断为零。
传递现成的绑定
当您需要完整的绑定功能集 - 反射绑定 (Binding)、预构建的编译绑定、TemplateBinding、MultiBinding 或 relative-source/element-name 绑定 - 每个生成的属性、附加属性和样式设置器还会公开接受 BindingBase 的重载直接:
using Avalonia.Data;
new TextBlock()
.Text(new Binding("ReflectionProperty")) // DataContext-relative reflection binding
.Foreground(new Binding("Theme.Accent") { Source = appState }); // explicit source
new TextBlock()
.Text(CompiledBinding.Create<MyViewModel, string>(x => x.Title, source: vm));
// attached properties and styles get the same overload
new Border().Grid_Row(new Binding(nameof(vm.Row)) { Source = vm });
new Style<TextBlock>().Text(new Binding(nameof(vm.Name)));
这是强类型 x => x.Member 表达式重载未涵盖的任何内容的逃生口(在绑定上传递的自定义转换器、RelativeSource、ElementName、字符串格式、多值绑定等)。通过 control.BindValue(TextBlock.TextProperty, binding) 在任何 AvaloniaProperty 上都可以使用相同的功能。
热重载支持
-
ViewBase支持.NET 6.0+ 热重载。 -
在没有 XAML 的程序集中保留声明性视图仍然可以产生最流畅的热重载体验。
-
当前的 Avalonia 和 .NET 工具链在同一应用程序中混合 AXAML 和 C# 标记方面要好得多,因此限制比以前小得多。
-
要显式启用 AMD 热重载集成:
AppBuilder.Configure<Application>() .UseHotReload() .SetupWithLifetime(lifetime);
AI代理工装(MCP)
可选的 仅限开发 Declarative.Avalonia.AgentTools 包运行进程内 MCP (模型
上下文协议)服务器在调试版本中的环回上,因此在 UI 上迭代的 AI 代理可以查看并
驱动正在运行的应用程序 — 关闭编辑 → 热重载 → 验证循环,无需人工中继
窗口看起来像。
using Declarative.Avalonia.AgentTools; // under #if DEBUG
AppBuilder.Configure<App>()
.UsePlatformDetect()
#if DEBUG
.UseAgentInspector() // loopback MCP server on 127.0.0.1:5599
#endif
.SetupWithLifetime(lifetime);
它公开了屏幕截图(使用 before/after 像素差异)、具有边界的视觉树和单个
绝对客户端-DIP 坐标系 (abs/center) 由每个工具共享,每个控件布局报告,
自动布局审核、属性/属性源/视图模型检查、像素↔控制命中测试
(带有“如何驱动此控件”提示)以及最近的 build/binding/runtime 错误。选择加入层
(EnableInteraction) 还驱动应用程序 — 真实合成的 pointer/keyboard 输入 (tap、drag、
pointer_*,甚至可以在没有自动化对等的自定义控件上工作),单击、键入、选择、调整大小,
切换主题,打开一个关闭的弹出窗口 - 加上一个逃生舱口(带有结构化的、可操作的错误)来设置
查看模型属性或直接运行命令以达到尴尬的状态。
将调用保留在 #if DEBUG 下:该包会拉入 Web 堆栈和远程控制界面,并且不得
发布中的船舶;它仅绑定到环回。完整信息请参见 docs/agent-tools.md
指导。
在代理中启用 MCP
检查器是 http://127.0.0.1:5599 上的可流式-HTTP MCP 服务器,因此每个代理都指向
相同的URL。在 dotnet watch 下运行应用程序,以便代理的编辑热重载到它检查的进程中。
克劳德代码 — claude mcp add --transport http avalonia-agent-inspector http://127.0.0.1:5599,或
项目 .mcp.json:
{ "mcpServers": { "avalonia-agent-inspector": { "type": "http", "url": "http://127.0.0.1:5599" } } }
opencode — 在 opencode.json 中的 mcp 下(远程服务器使用 type: "remote"):
{ "mcp": { "avalonia-agent-inspector": { "type": "remote", "url": "http://127.0.0.1:5599", "enabled": true } } }
Codex — ~/.codex/config.toml 中的 [mcp_servers.*] 表(url 使其可流化-HTTP;启用
RMCP 客户端使用 [features] → experimental_use_rmcp_client = true):
[mcp_servers.avalonia-agent-inspector]
url = "http://127.0.0.1:5599"
请参阅 docs/agent-tools.md 了解标头、项目范围的变体、
以及完整的工具参考。
为您自己和外部控件生成源代码
该软件包附带了源生成器,该生成器可生成以下标记扩展:
- 引用Avalonia框架组件
- 在您自己的项目中声明的控件
- 选择加入的第三方程序集
如果您下载了源代码或克隆了此存储库,请将源生成器项目添加为分析器参考:
<ItemGroup>
<ProjectReference Include="....Avalonia.Markup.Declarative.SourceGeneratorAvalonia.Markup.Declarative.SourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
确保源生成器项目的路径相对于您的项目是正确的。
注意:如果您将此库用作 NuGet 包,则会自动包含源生成器。
外部库支持
框架扩展会自动为您的项目引用的受支持的 Avalonia 程序集生成。要为第三方库生成扩展,请添加指向该程序集中任何类型的程序集属性:
using Avalonia.Markup.Declarative;
using ReactiveUI.Avalonia;
[assembly: GenerateMarkupExtensionsForAssembly(typeof(RoutedViewHost))]
不再需要独立工具安装或手动 avalonia-amd-gen 步骤。
-
09.11
tui-realm:实践指南
-
09.11
carp:实践指南
-
09.11
Coldfire:实践指南
-
09.11
Swell:实践指南
-
09.11
logcat:实践指南
-
09.11
simplefs:实践指南
-
- awesome-crypto:实践指南
- 09.11
-
-
-
-
下载
- |
-
-
下载
- 《行尸走肉第一章》免安装中文汉化硬盘版下载
- 单机|436 MB
- 一款以动作冒险为主题的游戏
-
-
下载
- 《街头霸王X铁拳》免安装中文汉化硬盘版下载
- 单机|111MB
- 一款非常好玩的格斗游戏
-
-
下载
- |
-
-
下载
- 《暗黑破坏神3》免安装繁体中文正式版下载
- 单机|7630 MB
- 一款以角色扮演为主题的游戏
-
-
下载
- 《马克思佩恩3》免安装硬盘版下载
- 单机|27033 MB
- 一款以第三人称射击为主题的游戏