Avalonia 在 C# 中获得 ResourceDictionary 资源字典和 DataTemplate 数据模板对象的通用方法
Avalonia 在 C# 中获得 ResourceDictionary 资源字典和 DataTemplate 数据模板对象的通用方法
一、前言
我们在进行一些动态构造的时候,其中一些函数参数要求传递 IDataTemplate 的对象,而 DataTemplate 作为一个以 xaml 定义的对象,我们一般是无法在 C# 中访问到的。
和 WPF 不一样,Avalonia 的 ResourceDictionary 的实例化也并不容易,特别是如果我们的处理是在 ViewModel 的地方时,你知道的,ViewModel 和 View 的分层和独立让 ViewModel 在框架设计上完全无法触摸 View 的分毫。
本文要介绍的是在 Avalonia 的 C# 编码部分如何获得 DataTemplate 对象的解决方法。
二、从创建资源字典开始
1. 资源字典的创建
我们使用的是 Visual Studio 2022,我尚不清楚如果你使用的是 Visual Studio Code,你该如何创建一个资源字典。关于资源的创建,其实我在 https://www.cnblogs.com/fanbal/articles/18186938 中有提到,但是为了你阅读方便,我们还是在这里也提供一个示例。
我们的教程项目是一个干净的 Avalonia 空白项目,项目的名字叫做 HowGetResDict。
它的结构是这样的:

请在项目中创建一个名为 ResourceDictionaries 的文件夹,然后在文件夹中新建资源字典项:

如果你不知道怎么新建资源字典项,你可以参考这个界面:

2. 资源字典的内容
资源字典中的内容非常简单,实际上就只有一个表达 TextBlock 的 DataTemplate。
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DataTemplate x:Key="TestDataTemplate">
<TextBlock Text="1111" />
</DataTemplate>
</ResourceDictionary>
我当然欢迎和推荐你在这里填入更多东西用来测试,如果你对 WPF 很熟悉的话,你会知晓,其实 DataTemplate 和 double、FontFamaily 等是没有太大差异的,我在之前写 WPF 的时候,喜欢将 Style 样式的 ControlTemplate 拆出来,Style 样式的部分以 StaticResource 绑定的形式给 Setter ,用以减少资源字典的缩进。
但是代价就是你必须为拆除来的 ControlTemplate 进行独立的命名,命名是一件很繁琐的事情,所以在后来我和缩进妥协了,选择最开始在 Style 中 Setter.Value 内部嵌入 ControlTemplate 的风格,毕竟编辑器能够折叠,如果将它们拆开,虽然会减少缩进但是会让折叠量翻倍,于是作罢。
三、在 App 中定义
在 App 中定义有两种风格:Avalonia XAML 和 AvaloniaResource
1. Avalonia XAML
默认的情况是使用 Avalonia XAML 进行资源的加载的。
在这种情况下你在 App.axaml 中的写法可以参考这个样子:
<Application
x:Class="HowGetResDict.App"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
<Application.Styles>
<FluentTheme />
</Application.Styles>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceInclude Source="/ResourceDictionaries/MyResourceDictionary.axaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
具体请看<ResourceInclude Source="/ResourceDictionaries/MyResourceDictionary.axaml" /> 这一块内容。
Source URL 书写的时候有斜杠////////////不要看漏了!!!
2. AvaloniaResource
我其实会推荐你使用 AvaloniaResource 来进行填写,因为这种做法不会漏斜杠。
我们来看一下写法
<Application
x:Class="HowGetResDict.App"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
<Application.Styles>
<FluentTheme />
</Application.Styles>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceInclude Source="avares://HowGetResDict/ResourceDictionaries/MyResourceDictionary.axaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
和上面的代码片段的差异同样在 ResourceInclude 的部分,这块内容变为了
<ResourceInclude Source="avares://HowGetResDict/ResourceDictionaries/MyResourceDictionary.axaml" />
在这种情况下你需要将资源字典的属性进行一些修改,修改其中的生成操作:

四、在 C# 中获得 ResourceDictionary 资源字典 和定义了的 DataTemplate 数据模板的方法
思路上是通过获取全局的 App 单例对象来实现 xaml 和 C# 的连接,如何获得 App 你当然可以有很多中方法,是目前最简单的通过 App 静态对象也好,还是使用你注册得到的容器来获得相应的单例也好,这边代码的意思是希望你能通过 App 来解决问题,至于怎么拿到 App,各位可以各显神通。
1. 错误的写法
请不要使用直接访问索引器的方式、不要使用类似 resDict["XXX"] 的方式来访问。
大概率,这是访问不到的,此乃我的经验和观察。
private void Test()
{
var topResources = App.Current.Resources;
// 别用这种方式,索引器在这里是无效的。
var testDataTemplate = topResources["TestDataTemplate"] as IDataTemplate;
}
你看,确实是空的, null,找不着吧。

2. 正确的做法
请使用 TryGetResource 来进行访问:
private void Test()
{
var topResources = App.Current.Resources;
if (topResources.TryGetResource("TestDataTemplate", theme: null, out var outDataTemplate))
{
var dataTemplate = outDataTemplate as IDataTemplate;
}
}
像是这样子就可以拿到我们想要的 DataTemplate 对象了。

五、总结
如果你想要拿到写在 ResourceDictionary 资源字典的 DataTemplate 资源字典,你需要经过以下的一些步骤:
- 确保你的 ResourceDictionary 资源字典里面确实写了一个合法的 DataTemplate 资源字典;
- 在 App.axaml 中引入你的 ResourceDictionary 资源字典,以正确的方式提供 Source URL;
- C# 代码的部分获得最顶层的 App 对象,然后以正确的方式调用。

浙公网安备 33010602011771号