Avalonia资源拿捏方式探索笔记

002 Avalonia资源拿捏方式探索笔记

版本 Avalonia 11.0

0. 参考资料

  1. Avalonia 如何使用资源 https://docs.avaloniaui.net/zh-Hans/docs/guides/styles-and-resources/resources

1. 前言

在写 WPF 的时候,后期的资源管理必须要涉及资源管理的部分,这对于一个不小的项目来说是极为必要的。
但是我在使用 Avalonia 的时候,发现 Avalonia 对于资源和实例的创建和 WPF 很大,很多 WPF 中有点黑的操作在 Avalonia 中都不能使用,为此开一篇文章来将我收集的一些使用方法整理在这里。

2. 资源创建和使用的 WPF 回忆与初尝试

说实话,上来我就被 Avalonia 的资源创建整不会了。关于命名空间也相当的陌生。
我在学习 WPF 的时候,上来的教程似乎是关于颜色的资源创建。


<Window x:Class="Test01.Views.MainWindow"
        xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:views="clr-namespace:Test01.Views"
        xmlns:vm="using:Test01.ViewModels"
        Title="Test01"
        Width="300"
        Height="200"
        Icon="/Assets/avalonia-logo.ico"
        mc:Ignorable="d">

    <Window.Resources>
        <ResourceDictionary>
            <SolidColorBrush x:Key="ThisSolidColorBrush" Color="Red" />
        </ResourceDictionary>
    </Window.Resources>

    <Grid Background="{StaticResource ThisSolidColorBrush}">
        <views:MainView />
    </Grid>

</Window>


001.png

答案是效果不错。确实绑定的东西都在,只是 Avalonia 的智能编辑器不是很理想,很多时候是靠编写 WPF 的经验摁敲出来的。

3. 字符串如何创建

字符串在 WPF 的创建需要引入 System 的命名空间,而我对 Avalonia 的命名空间体系略有陌生,而且智能提示的缺失也让我一定程度上寸步难行。
而在 Avalonia 中,创建字符串资源我是在 https://docs.avaloniaui.net/zh-Hans/docs/guides/styles-and-resources/resources 中的最后才看到的,文中使用了 <x:String x:Key="TheKey">HelloWorld</x:String> 这个的写法。

注意看,x:Stringx:Key,难道说 x 在 Avalonia 里面也纳入了 System 的命名空间吗,带着这种想法,我试了一下 String 资源的创建,确实没有什么问题。

<Window x:Class="Test01.Views.MainWindow"
        xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:views="clr-namespace:Test01.Views"
        xmlns:vm="using:Test01.ViewModels"
        Title="Test01"
        Width="300"
        Height="200"
        Icon="/Assets/avalonia-logo.ico"
        mc:Ignorable="d">

    <Window.Resources>
        <ResourceDictionary>
            <x:String x:Key="ThisKey">hello</x:String>
        </ResourceDictionary>
    </Window.Resources>

    <Grid>
        <views:MainView />
        <TextBlock Text="{StaticResource ThisKey}" />
    </Grid>

</Window>

4. Double 等资源也可以吗

我在尝试定义 double 变量,它们可能也在 x 中被写出来。


<Window x:Class="Test01.Views.MainWindow"
        xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:views="clr-namespace:Test01.Views"
        xmlns:vm="using:Test01.ViewModels"
        Title="Test01"
        Width="300"
        Height="200"
        Icon="/Assets/avalonia-logo.ico"
        mc:Ignorable="d">

    <Window.Resources>
        <ResourceDictionary>
            <x:Double x:Key="WidthKey">100</x:Double>
            <x:Double x:Key="HeightKey">50</x:Double>
        </ResourceDictionary>
    </Window.Resources>

    <Grid>
        <views:MainView />
        <Button Width="{StaticResource WidthKey}" Height="{StaticResource HeightKey}" />
    </Grid>

</Window>

5. 数据模板 DataTemplate 的资源化

众所周知,在 WPF 里面有 DataTemplate 的概念,在早期我会用一种奇怪的方法去可视化我的 ViewModel。
总之这需要一个 ViewModel,让我们来创建一个 ViewModel。


///<summary>TestViewModel</summary>
public partial class TestViewModel : ViewModelBase
{
    #region props

    ///<summary>标题。</summary>
    public string Title { get => _title; set => SetProperty(ref _title, value); }
    private string _title = "测试标题";

    ///<summary>正文文本。</summary>
    public string Content { get => _content; set => SetProperty(ref _content, value); }
    private string _content = "测试文本";

    #endregion

}

然后我整个 DataTemplate 来做。

<Window x:Class="Test01.Views.MainWindow"
        xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:views="clr-namespace:Test01.Views"
        xmlns:vm="using:Test01.ViewModels"
        Title="Test01"
        Width="300"
        Height="200"
        Icon="/Assets/avalonia-logo.ico"
        mc:Ignorable="d">

    <Window.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="TestViewModelDataTemplate" DataType="{x:Type vm:TestViewModel}">
                <Grid Width="100"
                      Height="100"
                      RowDefinitions="1*,1*">
                    <Border Grid.RowSpan="2"
                            BorderBrush="Red"
                            BorderThickness="1" />

                    <TextBlock Grid.Row="0" Text="{Binding Title}" />
                    <TextBlock Grid.Row="1" Text="{Binding Content}" />

                </Grid>
            </DataTemplate>
        </ResourceDictionary>
    </Window.Resources>

    <Grid>
        <!--<views:MainView />-->
        <ContentControl Content="{x:Static vm:TestViewModel.Instance}" 
						ContentTemplate="{StaticResource TestViewModelDataTemplate}" />
    </Grid>

</Window>

结果是这样的

6. 特定样式的可使用资源(似乎不太重要,有一些意外的地方)

在 Avalonia 中因为引入了自己的样式概念,所以在 Avalonia 中,资源有了一些归属的区分。
似乎在 Avalonia 的资源字典体系中,所有都是需要一个 x:Key,所以一个 Style 的定义可以放在 Avalonia 定义的 Styles 里面。

<Window x:Class="Test01.Views.MainWindow"
        xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:views="clr-namespace:Test01.Views"
        xmlns:vm="using:Test01.ViewModels"
        Title="Test01"
        Width="300"
        Height="200"
        Icon="/Assets/avalonia-logo.ico"
        mc:Ignorable="d">

    <Window.Styles>
        <Style Selector="TextBlock.test">
            <Style.Resources>
                <SolidColorBrush x:Key="ThisTextBlockSolidColorBrush" Color="Red" />
            </Style.Resources>
        </Style>
    </Window.Styles>

    <Grid>
        <!--<views:MainView />-->
        <TextBlock Background="{StaticResource ThisTextBlockSolidColorBrush}"
                   Classes="test"
                   Text="111" />
    </Grid>

</Window>

虽然上面有指定 classes,但是我发现,即时把 Classes 给去掉,似乎也是可行。

而且居然不是 TextBlock ,而是 Button 居然也可以?!

7. 如何在同项目中的资源字典中获取资源?

为此我新建了一个资源字典名叫 ResourceDictionaries/TestResourceDictionary.axaml


<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <!--  Add Resources Here  -->

    <SolidColorBrush x:Key="TestSolidColorBrush" Color="Red" />

</ResourceDictionary>

我尝试在我的 Window.axaml 中引用,但是结果出错了。

提示是这样的。
Avalonia.Markup.Xaml.XamlLoadException:“No precompiled XAML found for ResourceDictionaries/TestResourceDictionary.axaml (baseUri: avares://Test01/Views/MainWindow.axaml), make sure to specify x:Class and include your XAML file as AvaloniaResource”

可是明明我的属性和其他 axaml 一样,都是 Avalonia XAML 呀。我在尝试寻找原因。

为什么我的 <ResourceInclude Source="ResourceDictionaries/TestResourceDictionary.axaml" /> 引用不对呢,我在寻找原因,后来我仔细看到详细的错误描述:

Unable to resolve XAML resource "avares://Test01/Designer/ResourceDictionaries/TestResourceDictionary.axaml" in the "Test01" assembly. Make sure this file exists and is public. Line 17, position 34.

为什么我的资源被认为是来自 Test01/Designer 呢,难道是我写的还不够完整吗?

于是我看了一下官方文档的示例,好家伙,还得在前面加 / 啊!

正确的写法是这样的: <ResourceInclude Source="/ResourceDictionaries/TestResourceDictionary.axaml" />,你发现改了哪里了吗?答案就是在前面加了一个斜杠 /

8. 如何在自定义类库中获取资源字典和资源?

新建一个类库,我的 Avalonia 是 .NET 7,为此对应我建一个 .NET 7 的普通类库,注意,普通类库就可以了,我的类库叫做 TestLib01

随后我建立了一个资源字典 ResourceDictionaries/LibTestResourceDictionary.axaml 资源字典。

<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <!--  Add Resources Here  -->
    <SolidColorBrush x:Key="LibTestSolidColorBrush" Color="Blue" />
</ResourceDictionary>
 

然后我在 MainWindow.xaml 里面这样调用。

<Window x:Class="Test01.Views.MainWindow"
        xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:views="clr-namespace:Test01.Views"
        xmlns:vm="using:Test01.ViewModels"
        Title="Test01"
        Width="300"
        Height="200"
        Icon="/Assets/avalonia-logo.ico"
        mc:Ignorable="d">

    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceInclude Source="avares://TestLib01/ResourceDictionaries/LibTestResourceDictionary.axaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <Grid>
        <TextBlock Background="{StaticResource LibTestSolidColorBrush}" />
    </Grid>

</Window>

posted @ 2024-05-11 17:51  fanbal  阅读(1203)  评论(0)    收藏  举报