Avalonia extensions for event binding using Source Generators + High Performance VirtualizingWrapPanel.
- v:Event - 简洁的事件绑定标记扩展
- v:RoutedEvent - 绑定路由事件到 ViewModel
- v:RawEvent - 处理非 EventArgs 事件(如 WindowClosing)
- Attributes - EventBind, CopyTo, Compare, Table, Column, PrimaryKey, SqliteConfig, etc.
- SQLite Source Generator - 编译时生成 DbContext + 迁移管理器,支持 11 项 PRAGMA 配置
- VirtualizingWrapPanel - 高性能虚拟化 WrapPanel(.NET 10 / C# 12+ 优化)
<PackageReference Include="Finnonly.Avalonia" Version="1.0.12-rc1" />
<PackageReference Include="Finnonly.SourceGenerator" Version="1.0.12-rc1" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />Avalonia 12 支持:从 1.0.11 开始,Finnonly 支持 Avalonia 12.0.0-rc1+。 Avalonia 12 默认启用编译型绑定(Compiled Bindings),XAML 中需要声明
x:DataType指令。 内部 API 变更:IBinding→BindingBase,BindingOperations.Apply()→AvaloniaObject.Bind()。
v:Event 是最简洁的事件绑定方式,自动推断事件类型。
- 🎯 智能推断 - 自动识别路由事件和普通事件
- 📝 简洁语法 - 一个标记扩展处理所有事件
- 🔗 直接绑定 - 无需 Command,直接绑定 ViewModel 方法
- ⚡ 源生成器 - 编译时生成代码,零运行时反射开销
<Window xmlns:v="using:Finnonly.Avalonia"
x:DataType="local:MainViewModel"
Loaded="{v:RoutedEvent OnLoaded}"
Closing="{v:RawEvent OnClosing}">
<StackPanel>
<Button Content="点击" Click="{v:RoutedEvent OnButtonClick}"/>
<Button Content="点击" Click="{v:RoutedEvent OnButtonClick,'!sender'}"/>
<Button Content="点击" Click="{v:RoutedEvent OnButtonClick,'!args'}"/>
<Button Content="点击" Click="{v:RoutedEvent OnButtonClick,'!sender','!args'}"/>
<TextBox TextChanged="{v:RoutedEvent OnTextChanged}"/>
<ListBox SelectionChanged="{v:RoutedEvent OnSelectionChanged}"/>
</StackPanel>
</Window>// ViewModel
public partial class MainViewModel : ViewModelBase
{
[EventBind]
public void OnLoaded()
{
// 窗口加载完成
}
[EventBind]
public void OnClosing()
{
// 窗口关闭前
}
[EventBind]
public void OnButtonClick()
{
// 按钮点击
}
[EventBind]
public void OnTextChanged(object sender, TextChangedEventArgs e)
{
// 文本变化,可选参数
}
[EventBind]
public void OnSelectionChanged()
{
// 选择变化
}
}// 无参数 - 最简洁
[EventBind]
public void OnClick() { }
// 只有 sender
[EventBind]
public void OnClick(object sender) { }
// 完整参数
[EventBind]
public void OnClick(object sender, RoutedEventArgs e) { }
// 异步方法
[EventBind]
public async Task OnClickAsync()
{
await DoSomethingAsync();
}针对特定场景的专用标记扩展。
用于明确绑定 Avalonia 路由事件。
<Window Loaded="{v:RoutedEvent OnLoaded}"
Unloaded="{v:RoutedEvent OnUnloaded}">
<Button Click="{v:RoutedEvent OnButtonClick}"/>
</Window>用于处理特殊的非标准事件(如 WindowClosing)。
<Window Closing="{v:RawEvent OnWindowClosing}">[EventBind]
public void OnWindowClosing()
{
// 可以取消关闭
}编译时自动生成 SQLite 数据库上下文(SqliteDbContext)和迁移管理器(SqliteMigrationManager),零反射、零手写 SQL。
[Table("users")]
[Migration(1)]
public class User
{
[PrimaryKey(true)]
public int Id { get; set; }
[Column("user_name")]
public string Name { get; set; } = string.Empty;
public string? Email { get; set; }
[Ignore]
public string DisplayName => $"{Name} <{Email}>";
}通过 [assembly: SqliteConfig] 属性配置数据库性能参数,不配置则使用性能优化的默认值:
// 默认配置(开箱即用,已针对性能优化)
// 无需任何代码
// 自定义配置示例
[assembly: SqliteConfig(
JournalMode = "WAL", // 日志模式(默认 WAL)
Synchronous = "NORMAL", // 同步模式(默认 NORMAL)
CacheSize = -8000, // 缓存 8MB(默认 -8000)
TempStore = "MEMORY", // 临时存储(默认 MEMORY)
MmapSize = 536870912, // 内存映射 512MB(默认)
BusyTimeout = 5000, // 忙等待 5s(默认 5000)
ForeignKeys = true, // 外键约束(默认 true)
AutoVacuum = "INCREMENTAL", // 自动回收(默认 INCREMENTAL)
WalAutoCheckpoint = 2000, // WAL 检查点间隔(默认 2000)
PageSize = 4096, // 页大小(默认 4096)
SecureDelete = false // 安全删除(默认 false)
)]using var db = new SqliteDbContext("Data Source=app.db");
// CRUD
await db.InsertUserAsync(user);
var user = await db.GetUserByIdAsync(1);
var all = await db.GetAllUserAsync();
await db.UpdateUserAsync(user);
await db.DeleteUserAsync(1);
// Upsert
await db.InsertOrUpdateUserAsync(user);
await db.BulkInsertOrUpdateUserAsync(users);
// 条件查询
var result = await db.GetUserByConditionAsync(
"user_name = @name",
new[] { new SqliteParameter("@name", "finn") });
// 分页
var page = await db.GetUserListByConditionAsync(
"1=1", Array.Empty<SqliteParameter>(),
orderBy: "Id DESC", limit: 20, offset: 0);高性能虚拟化 WrapPanel,专为 .NET 10 / C# 12+ 优化,支持大量数据的流畅滚动。
- 🚀 高性能虚拟化 - 仅渲染可见元素,支持万级数据流畅滚动
- 📐 固定/自适应尺寸 - 支持固定项目大小或自动测量
- 📏 自定义间距 - 支持水平和垂直间距配置
- 🔄 无闪烁刷新 - 集合变化时平滑过渡
- ⚡ 防抖优化 - 尺寸变化时使用防抖减少重绘
- 📜 加载更多 - 内置滚动到底部加载更多数据支持
<Window xmlns:v="using:Finnonly.Avalonia"
x:DataType="local:MainViewModel">
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<v:VirtualizingWrapPanel
EstimatedItemWidth="200"
EstimatedItemHeight="300"
ItemHorizontalSpacing="8"
ItemVerticalSpacing="8"
UseFixedItemSize="True"
FillAvailableSpace="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="LightBlue" CornerRadius="8">
<TextBlock Text="{Binding Title}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Window>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
EstimatedItemWidth |
double | 200 | 预设项目宽度(用于虚拟化计算) |
EstimatedItemHeight |
double | 200 | 预设项目高度 |
ItemHorizontalSpacing |
double | 0 | 项目水平间距 |
ItemVerticalSpacing |
double | 0 | 项目垂直间距 |
UseFixedItemSize |
bool | true | 是否使用固定尺寸(忽略实际测量) |
FillAvailableSpace |
bool | true | 是否填充满整个可用空间 |
| 事件 | 说明 |
|---|---|
LoadMoreRequested |
滚动到底部时触发,用于加载更多数据 |
// XAML
<v:VirtualizingWrapPanel
x:Name="VPanel"
HasMoreItems="True"/>
// Code-behind or ViewModel
VPanel.LoadMoreRequested += async (s, e) =>
{
await LoadMoreDataAsync();
};// ✅ 推荐:使用 ObservableCollection
public ObservableCollection<ItemModel> Items { get; } = new();
// 刷新数据(自动触发UI更新)
public void RefreshData()
{
Items.Clear();
foreach (var item in newData)
{
Items.Add(item);
}
}- 使用固定尺寸 - 设置
UseFixedItemSize="True"避免测量开销 - 合理设置缓冲区 - 控件默认缓冲 5 行元素,减少频繁创建/销毁
- 简化 ItemTemplate - 避免复杂嵌套和重型绑定
- 分批加载 - 利用
LoadMoreRequested实现分页加载
- 控件必须放在
ScrollViewer内部 ScrollViewer需要设置HorizontalScrollBarVisibility="Disabled"- 集合变化时会自动强制刷新,无需手动处理
MIT