Avalonia 避坑经验总结

一、命名空间

1.命名空间差异

<!--WPF-->
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
</Window>

<!--Avalonia-->
<Window xmlns="https://github.com/avaloniaui">
  
</Window>

2.本地命名空间写法不同

<!--WPF-->
xmlns:local="clr-namespace:myApp"
<!--Avalonia(推荐)-->
xmlns:local="using:myApp"

3.文件扩展名不同

  • WPF: .xaml/.xaml.cs
  • Avalonia: .axaml/.axaml.cs

二、样式系统

1. 没有Trigger,用选择器+伪类

WPF(Trigger) Avalonia(选择器+伪类)
Style.Triggers 伪类 :pointerover,:pressed,:disabled
DataTrigger 绑定伪类[(vm:MyViewModel.IsActive)]
EventTrigger Style.Animations
VisualStateManager 伪类系统
示例对比
<!--WPF DataTrigger-->
<DataTrigger Binding="{Binding IsError}" Value="True">
    <Setter Property=Foreground" Value="Red" />
</DataTrigger>

<!--Avalonia:绑定伪类-->
<Style Selector="Border[IsError=true]">
   <Setter Property="BorderBrush" Value="Red" />
</Style>

2. 样式用Selector 不用TargetType

<!--WPF-->
<Style TargetType="Button">
   <Setter Property="Background" Value="Blue" />
</Style>

<!--Avalonia-->
<Style Selector="Button">
    <Setter Property="Background" Value="Blue" />
</Style>

<!--带有类名的样式 类似WPF中指定了Key-->
<Style Selector="Button.primary">
    <Setter Property="Background" Value="Blue" />
</Style>
<!--使用时-->
<Button Class="primary" Content="确定" />  

3. 没有BaseOn,选择器自动组合

Avalonia 的样式选择器会自动叠加,不需要BaseOn显式继承

三、属性系统:相似但不同

1. DependencyProperty->StyledProperty/DirectProperty

WPF Avalonia 说明
DependencyProperty StyledProperty 依赖属性:支持样式、动画、继承
- DirectProperty 性能更好,但不支持样式、动画
DependencyProperty.Register() AvaloniaProperty.Register<TOwner,TValue> 泛型注册

注册示例

//WPF
public static readonly DependencyProperty TextProperty=DependencyProperty.Register(nameof(Text),typeof(string),typeof(MyControl),new PropertyMetadata(""));

//Avalonia
public static readonly StyledProperty<string> TextProperty=AvaloniaProperty.Register<MyControl,string>(nameof(Text),defaultValue:"");

2.PasswordBox 的Password 不是依赖属性

坑:想给PasswordBox.Password做双向绑定,结果永远是空
解决方案:用附加属性封装,或直接用事件处理

四、数据绑定:语法有差异

1.绑定语法简写

WPF Avalonia 说明
{Binding RelativeSource={RelativeSource Self}} 绑定自身
{Binding RelativeSource={RelativeSource AncestorType=Grid}} 绑定父级
绑定控件
{Binding RelativeSource={RelativeSource TemplateParent}} 模板绑定

2.编译时绑定(推荐)

Avalonia 支持 CompiledBinding,编译期就能检查绑定错误,强烈建议开启

<Window x:CompileBinding="True">

3. 绑定多打括号会失效

{Binding User.Name()} 多打了(),数据不显示
注意: 绑定属性不能加括号,绑定方法才加括号

五、控件差异:不是1:1 对应

1. 需要额外安装的控件

控件 说明
DataGrid 需要安装Avalonia.Controls.DataGrid Nuget 包
TreeView 内置 HierarchicalDataTemplate 改叫TreeDataTemplate

2. 没有直接对应的控件

WPF Avalonia 替代方案
ListView 用ListBox+ItemTemplate
StatusBar 自己用Panel样式实现
RichTextBox 用第三方编辑器
RoutedCommand 用ICommand实现(推荐CommunityToolkit.Mvvm)
WindowsFormsHost 不支持,必须用Avalonia原生控件

3. ToolTip用法不同

<!--WPF-->
<Button ToolTip="提示文字" />
<!--Avalonia-->
<Button ToolTip.Tip="提示文字" />

4.Visibility不同

WPF Avalonia 说明
Visibility.Visible IsVisible="True" 显示
Visibility.Collapsed IsVisible="False" 隐藏且不占空间
Visibility.Hidden Opcity="0" 隐藏但占用空间

六、资源与资源字典

1.资源引用协议不同

<!--WPF-->
<Image Source="pack://application:,,,/Assets/logo.png" />
<!--Avalonia-->
<Image Source="avares://YourApp/Assets/logo.png" />

2.Build Action 必须设为AvaloniaResource

坑: 新建的XAML 资源文件默认Build Action 是None,启动报错“找不到资源”
解决: 右键文件-属性-生成操作-选择AvaloniaResource

3.StaticResource 必须先定义后引用

坑: WPF会自动查找后面的资源,Avalonia不会
解决: 资源字典合并按依赖顺序排列,或改用DynamicResource

七、布局与跨平台差异

1.StackPanel 嵌套过多会卡顿

坑: Linux 上StackPanel 嵌套3层以上,滚动时CPU飙升
建议:

  • 复杂列表用ListBox/DataGrid+虚拟化
  • 嵌套不超过2层
  • 优先使用Grid

2.SizeToContent 在Linux上不准

坑: SizeToContent="WidthAndHeight" 在Linux上窗口尺寸跑偏
建议: Linux上手动设置固定尺寸,加MaxWidth /MaxHeight 限制

3. TextBox 换行在Linux上有问题

坑: TextWrapping="Wrap" 在Linux 上可能不生效
解决:

  • 加 MaxWidth 限制(别用Width=Auto)
  • 检查是否被ScrollView包裹(会禁止换行)

4.Canvas 绝对定位跨平台偏移

坑: DPI不同导致Canvas坐标偏移
建议: 优先用Grid+Margin 相对布局,避免Canvas 做复杂布局

八、跨平台常见坑

1、字体乱码

坑: Windows上的“微软雅黑”在Linux/MacOS 上乱码
解决方案:

  • 尝试用英文 "Microsoft YaHei"

2. 引用嵌入字体

<FontFamily x:Key="DefaultFont">
   avares://YourApp/Fonts/微软雅黑.ttf#微软雅黑,scans-serif
</FontFamily>

3. 加fallback 字体 (如: scan-serif)

4. 图片格式问题

坑: 16位深度PNG 在macOS上不显示
建议: 统一用8位PNG/JPG

5. 日期/数字格式不一致

解决:

  • 用StringFormat 显示指定格式
  • 全局设置统一文化 Thread.CurrentThread.CurrentCulture=CultureInfo.InvariantCulture

6. TabControl 切换内容丢失

坑: Avalonia默认切换Tab 时卸载内容以节省内存,输入的内容会丢失
解决:

<TabControl KeepAlive="True" />

7. Popup 点击外部不关闭

坑: Popup 直接放在Window下,StaysOpen="False" 不生效
解决: 把Popup放在Grid /StackPanel 等容器内

九、线程与调度

1. 后台线程直接用 Collection.Add(item) 抛异常

解决:

Application.Current.Dispatcher.Invoke(()=>collection.Add(item))

2. Dispatcher API略有不同

WPF Avalonia
Dispatcher.Invoke() Dispatcher.UIThread.InvokeAsync()
Dispatcher.BeginInvoke() Dispatcher.UIThread.Post()
Dispatcher.CheckAccess() Dispacher.UIThread.CheckAccess()
posted @ 2026-07-03 12:02  丹心石  阅读(43)  评论(0)    收藏  举报