当前位置: 首页 > ds >正文

从 WPF 到 Avalonia 的迁移系列实战篇3:ResourceDictionary资源与样式的差异与迁移技巧

从 WPF 到 Avalonia 的迁移系列实战篇3:ResourceDictionary资源与样式的差异与迁移技巧

我的GitHub仓库Avalonia学习项目包含完整的Avalonia实践案例与代码对比。
我的gitcode仓库是Avalonia学习项目。
文中主要示例代码均可在仓库中查看,涵盖核心功能实现与优化方案。
点击链接即可直接访问,建议结合代码注释逐步调试。

在 WPF 开发中,我们习惯了用 ResourceDictionary 作为统一的资源容器,里面既可以放普通资源(画刷、字符串、模板),也可以放样式(Style)。
但是当你迁移到 Avalonia 时,会发现它把 资源样式 分成了两块:ResourcesStyles。这一点如果不注意,很容易踩坑。本文将结合learningAvalonia仓库的示例,详细对比一下两者的差异,并给出迁移技巧。


一、WPF 中的 ResourceDictionary

在 WPF 中,ResourceDictionary 是一个“万能容器”,里面可以存放一切资源,包括:

  • 普通资源(颜色、画刷、模板等)
  • 控件样式(Style

1. WPF资源字典的典型结构

以仓库中WPF项目的资源文件为例:

  • 颜色与字体资源(ColorAndFomts.xaml):定义了颜色、画笔、字体样式等基础资源
<ResourceDictionaryxmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:system="clr-namespace:System;assembly=System.Runtime"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><!--  定义颜色  --><Color x:Key="PrimaryColor">#FF4CAF50</Color><SolidColorBrush Color="{StaticResource PrimaryColor}" x:Key="PrimaryColorBrush" /><Color x:Key="SecondaryColor">#FFC107</Color><SolidColorBrush Color="{StaticResource SecondaryColor}" x:Key="SecondaryColorBrush" /><Color x:Key="AccentColor">#FFEB3B</Color><SolidColorBrush Color="{StaticResource AccentColor}" x:Key="AccentColorBrush" /><!--  定义字体  --><FontWeight x:Key="BoldFontWeight">Bold</FontWeight><system:Double x:Key="DefaultFontSize">30</system:Double></ResourceDictionary>
  • 样式资源(blinkingButtonStyle.xaml):定义了控件样式,与其他资源存储在同类型的ResourceDictionary
<ResourceDictionaryxmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:control="clr-namespace:WpfDemo.control"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><Style TargetType="{x:Type control:BlinkingButton}"><Setter Property="Background"><Setter.Value><LinearGradientBrush EndPoint="1,1" StartPoint="0,0"><GradientStop Color="#00C3FF" Offset="0" /><GradientStop Color="#FF61A6" Offset="1" /></LinearGradientBrush></Setter.Value></Setter><Setter Property="Foreground" Value="White" /><Setter Property="FontWeight" Value="Bold" /><Setter Property="BorderThickness" Value="0" /><Setter Property="Padding" Value="12,6" /><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type control:BlinkingButton}"><Border Background="{TemplateBinding Background}" CornerRadius="20"><ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /></Border></ControlTemplate></Setter.Value></Setter></Style><!--  新增的 Button 样式  --><Style TargetType="{x:Type Button}" x:Key="RoundedButtonStyle"><Setter Property="Background" Value="LightBlue" /><Setter Property="Foreground" Value="White" /><Setter Property="FontWeight" Value="Bold" /><Setter Property="BorderThickness" Value="0" /><Setter Property="Padding" Value="12,6" /><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type Button}"><Border Background="{TemplateBinding Background}" CornerRadius="20"><ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /></Border></ControlTemplate></Setter.Value></Setter></Style></ResourceDictionary>

2. WPF中资源的合并与引用

<ApplicationStartupUri="MainWindow.xaml"x:Class="WpfDemo.App"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><Application.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="Themes/blinkingButtonStyle.xaml" /><ResourceDictionary Source="Themes/ColorAndFomts.xaml" /></ResourceDictionary.MergedDictionaries></ResourceDictionary></Application.Resources>
</Application>

在界面中引用时,无论是基础资源还是样式,都通过{StaticResource}

<ButtonBackground="{StaticResource SecondaryColorBrush}"Content="我是一个圆角按钮"FontSize="{StaticResource DefaultFontSize}"FontWeight="{StaticResource BoldFontWeight}"Grid.Row="2"Height="80"HorizontalAlignment="Center"Style="{StaticResource RoundedButtonStyle}"VerticalAlignment="Center"Width="300" />

3. WPF资源管理的特点

  • 资源与样式混合存储:颜色、画笔、样式等所有资源都在ResourceDictionary根节点下,仅通过x:Key区分。
  • 样式即资源Style是一种特殊的资源,必须通过x:Key(或TargetType隐式Key)标识,引用方式与其他资源一致。
  • 缺乏结构区分:大型项目中资源字典可能包含成百上千个对象,混合存储会导致维护困难。

在这种模式下,WPF 查找资源的规则是:
控件本地 → 上级容器 → 窗口 → 应用程序 → 系统/主题。

所以,WPF 开发者习惯了把所有资源都丢到一个字典里。


二、Avalonia中的ResourceDictionary:资源与样式的分离设计

Avalonia作为WPF的跨平台继承者,在资源管理上进行了针对性优化。其核心变化是:ResourceDictionary明确划分为Resources(基础资源)和Styles(样式集合)两个独立区域,使资源结构更清晰。

1. Avalonia资源字典的典型结构

Avalonia的ResourceDictionary通过两个子节点分离资源类型:

  • <Resources>:存储非样式资源(颜色、画笔、字体、数据等),与WPF中的基础资源对应。
  • <Styles>:专门存储Style对象,支持通过Selector(选择器)更灵活地定位目标控件。

以仓库中Avalonia项目的资源文件为例:

  • 颜色与字体资源(ColorAndFomts.xaml):定义了颜色、画笔、字体样式等基础资源,依然使用ResourceDictionary
<ResourceDictionaryxmlns="https://github.com/avaloniaui"xmlns:system="clr-namespace:System;assembly=System.Runtime"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><!--  Add Resources Here  --><!--  定义颜色  --><Color x:Key="PrimaryColor">#FF4CAF50</Color><SolidColorBrush Color="{StaticResource PrimaryColor}" x:Key="PrimaryColorBrush" /><Color x:Key="SecondaryColor">#FFC107</Color><SolidColorBrush Color="{StaticResource SecondaryColor}" x:Key="SecondaryColorBrush" /><Color x:Key="AccentColor">#FFEB3B</Color><SolidColorBrush Color="{StaticResource AccentColor}" x:Key="AccentColorBrush" /><!--  定义字体  --><FontWeight x:Key="BoldFontWeight">Bold</FontWeight><system:Double x:Key="DefaultFontSize">30</system:Double>
</ResourceDictionary>

样式资源(blinkingButtonStyles.xaml):定义了控件样式,必须放在 Styles 节点下,不能混在 Resources 中。

<Stylesxmlns="https://github.com/avaloniaui"xmlns:local="clr-namespace:AvaloniaDemo.Controls"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><Style Selector="local|BlinkingButton"><Setter Property="Background"><Setter.Value><LinearGradientBrush EndPoint="100%,100%" StartPoint="0%,0%"><GradientStop Color="#00C3FF" Offset="0" /><GradientStop Color="#FF61A6" Offset="1" /></LinearGradientBrush></Setter.Value></Setter><Setter Property="Foreground" Value="White" /><Setter Property="FontWeight" Value="Bold" /><Setter Property="BorderThickness" Value="0" /><Setter Property="Padding" Value="12,6" /><Setter Property="Template"><ControlTemplate><Border Background="{TemplateBinding Background}" CornerRadius="20"><ContentPresenterContent="{TemplateBinding Content}"ContentTemplate="{TemplateBinding ContentTemplate}"Foreground="{TemplateBinding Foreground}"HorizontalAlignment="Center"VerticalAlignment="Center" /></Border></ControlTemplate></Setter></Style><!--  新增的 Button 样式  --><Style Selector="Button.rounded"><Setter Property="Background" Value="LightBlue" /><Setter Property="Foreground" Value="White" /><Setter Property="FontWeight" Value="Bold" /><Setter Property="BorderThickness" Value="0" /><Setter Property="Padding" Value="12,6" /><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type Button}"><Border Background="{TemplateBinding Background}" CornerRadius="20"><ContentPresenterContent="{TemplateBinding Content}"HorizontalAlignment="Center"VerticalAlignment="Center" /></Border></ControlTemplate></Setter.Value></Setter></Style></Styles>

2. Avalonia中资源的合并与引用

Avalonia合并资源字典的方式与WPF类似,但内部会区分ResourcesStyles的合并:

<!-- AvaloniaDemo/App.axaml -->
<ApplicationRequestedThemeVariant="Default"x:Class="AvaloniaDemo.App"xmlns="https://github.com/avaloniaui"xmlns:local="using:AvaloniaDemo"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><!--  "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options.  --><Application.DataTemplates><local:ViewLocator /></Application.DataTemplates><!--  Styles:只能放 控件样式(Setter、ControlTemplate 等)  --><Application.Styles><FluentTheme /><StyleInclude Source="avares://AvaloniaDemo/Themes/BlinkingButtonStyles.axaml" /></Application.Styles><!--  Resources:只能放 非样式资源(Brush、字符串、数值等)。  --><Application.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceInclude Source="avares://AvaloniaDemo/Themes/ColorAndFonts.axaml" /></ResourceDictionary.MergedDictionaries></ResourceDictionary></Application.Resources>
</Application>

引用时,基础资源仍通过{StaticResource},而样式可*使用 CSS-like 选择器,例如:

样式的特点

  • 必须放在 Styles 节点下,不能混在 Resources 中。

  • 使用 CSS-like 选择器,例如:

     <ButtonBackground="{StaticResource SecondaryColorBrush}"Classes="rounded"Content="我是一个圆角按钮"FontFamily="{StaticResource DefaultFontFamily}"FontSize="{StaticResource DefaultFontSize}"FontWeight="{StaticResource BoldFontWeight}"Grid.Row="2"Height="80"HorizontalAlignment="Center"VerticalAlignment="Center"Width="300" />
    

三、迁移时的对比总结

功能WPF (ResourceDictionary)Avalonia (Resources & Styles)
普通资源存放ResourceDictionaryResources
样式存放ResourceDictionaryStyles
样式语法基于 TargetType / BasedOn基于 CSS-like Selector
动态资源引用{DynamicResource}{DynamicResource}(不常用)
合并资源字典<ResourceDictionary.MergedDictionaries><StyleInclude> / <ResourceInclude>

四、迁移技巧

  1. 把样式移到 Styles

    • WPF 中写在 ResourceDictionary 里的 Style,要迁移到 Avalonia 的 <Styles> 中。
    <!-- WPF -->
    <ResourceDictionary><Style TargetType="Button"><Setter Property="Background" Value="Red"/></Style>
    </ResourceDictionary><!-- Avalonia -->
    <Styles><Style Selector="Button"><Setter Property="Background" Value="Red"/></Style>
    </Styles>
    
  2. 普通资源依旧放在 Resources
    画刷、模板、字符串等写在 <Resources> 中,然后用 {StaticResource}{DynamicResource} 引用。

  3. 合并资源字典

    • WPF:

      <Application.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="Dictionary1.xaml"/></ResourceDictionary.MergedDictionaries></ResourceDictionary>
      </Application.Resources>
      
    • Avalonia:

      <Application.Styles><FluentTheme Mode="Light"/><StyleInclude Source="avares://MyApp/Styles/Button.axaml"/>
      </Application.Styles>
      
  4. 利用 CSS-like Selector 提升可维护性
    Avalonia 的 :hover:checked 等伪类可以取代 WPF 的触发器,更直观。


五、结语

WPF 中的 ResourceDictionary 是一个“万能大容器”,而 Avalonia 则通过把 ResourcesStyles 分离,让资源管理更清晰,结构更接近 Web 开发思路。

如果你正在从 WPF 迁移到 Avalonia,建议你先把样式统一放到 <Styles>,资源放到 <Resources>,这样能避免很多“为什么样式不起作用”的坑。

我的GitHub仓库Avalonia学习项目包含完整的Avalonia实践案例与代码对比。
我的gitcode仓库是Avalonia学习项目。
文中主要示例代码均可在仓库中查看,涵盖核心功能实现与优化方案。
点击链接即可直接访问,建议结合代码注释逐步调试。

http://www.xdnf.cn/news/19136.html

相关文章:

  • 使用 httpsok 工具全面排查网站安全配置
  • @HAProxy 介绍部署使用
  • Copilot、Cursor、Trae、ChatGPT 的“四件套”场景选择表
  • 5G相对于4G网络的优化对比
  • 卷积神经网络实现mnist手写数字集识别案例
  • 三、计算机网络与分布式系统(上)
  • Linux DNS配置文件resolv.conf简介
  • Centos 8 磁盘扩展xfs文件系统 (LVM)
  • 云计算学习100天-第32天
  • 1-ATSAMV71Q21
  • 大模型后训练——Online-RL实践
  • DistributedLock 实现.Net分布式锁
  • 智能养花谁更优?WebIDE PLOY技术与装置的结合及实践价值 —— 精准养护的赋能路径
  • 北斗导航 | 工信部印发《关于优化业务准入促进卫星通信产业发展的指导意见》解析
  • MySQL数据库精研之旅第十三期:吃透用户与权限管理,筑牢数据库安全第一道防线
  • 【MySQL数据库】存储引擎 学习记录
  • 高光谱成像在食品质量和安全检测中的应用
  • 【C++游记】子承父业——乃继承也
  • [p2p-Magnet] 队列与处理器 | DHT路由表
  • iOS文件管理在uni-app开发中的实战应用,多工具解决
  • hive on tez如果是2个大表union会写几次临时文件到hdfs目录,数据量如何计算
  • 密码管理中
  • 水果目标检测[2]:ALAD-YOLO:一种轻便、精确的苹果叶病检测仪
  • 学习Python中Selenium模块的基本用法(7:元素操作-1)
  • 【golang长途旅行第33站】常量------补充知识点
  • golang 12 package 和 module
  • Docker 入门指南:从基础概念到常见命令及高级工具详解
  • C++:知识点小结
  • vue2 watch 的使用
  • 从 WPF 到 Avalonia 的迁移系列实战篇1:依赖属性的异同点与迁移技巧