学习笔记(Maui 08 懒式初始化和事件转命令)

学习笔记(Maui 08 懒式初始化和事件转命令)

DailyPoetryM 项目(对应 P15)

本节通过 DailyPoetryM 项目讲解懒式初始化和事件转命令

1 异步实现 RelayCommand 方法

1.1 老版本

private RelayCommand _CommandNavigatedTo;
public RelayCommand CommandNavigatedTo => _CommandNavigatedTo ??= new RelayCommand(async () =>
{
    await CommandNaviagedToFunction();
});

1.2 新版本

private AsyncRelayCommand _CommandNavigatedTo;
public AsyncRelayCommand CommandNavigatedTo => _CommandNavigatedTo ??= new AsyncRelayCommand(async () =>
{
    await CommandNaviagedToFunction();
});

新版本使用 AsyncRelayCommand 代替 RelayCommand,直接指明异步操作。

private AsyncRelayCommand _CommandNavigatedTo;
public AsyncRelayCommand CommandNavigatedTo => _CommandNavigatedTo ??= new AsyncRelayCommand(() =>
{
    return CommandNaviagedToFunction();
});

这样似乎也可以。可以简化写法。

private AsyncRelayCommand _CommandNavigatedTo;
public AsyncRelayCommand CommandNavigatedTo => _CommandNavigatedTo ??= new AsyncRelayCommand(CommandNaviagedToFunction);

新版本的测试有空引用错误,未解决。

2 懒式初始化

占用大量资源的变量过早初始化,会占用大量内存,而这些变量未必会使用。这种资源占用的情况会影响程序执行。为了解决这种问题,这些变量定义时暂时不进行初始化,而是在这些变量使用时才进行初始化。这种初始化方式称为懒式初始化。懒式初始化体现了按需加载的工程思想。

private RelayCommand _CommandNavigatedTo;
public RelayCommand CommandNavigatedTo => _CommandNavigatedTo ??= new RelayCommand(async () =>
{
    await CommandNaviagedToFunction();
});

以上 RelayCommand 使用符号 ??= 是懒式初始化,即在使用时才赋值,??= 符号无法确定原子性。微软提供了标准化的懒式初始化,能够保证线程安全。

private Lazy<AsyncRelayCommand> _LazyCommandNavigatedTo;
public AsyncRelayCommand CommandNavigatedTo => _LazyCommandNavigatedTo.Value;

标准懒式初始化需要在构造函数里赋值。

_LazyCommandNavigatedTo = new Lazy<AsyncRelayCommand>(() => new AsyncRelayCommand(CommandNaviagedToFunction));

首次使用 AsyncRelayCommand 时,_LazyCommandNavigatedTo 调用 Value,从而执行 new AsyncRelayCommand(CommandNaviagedToFunction),创建 AsyncRelayCommand。

3 事件转命令

3.1 项目整理

删除被测试 Maui 项目 DailyPoetryM 的文件夹 Models、文件夹 ViewModels 和文件夹 Services 及其中所有内容。在被测试 Maui 项目 DailyPoetryM 的依赖性中引用中间库项目 DailyPoetryM.Library。
在被测试 Maui 项目 DailyPoetryM 中添加文件夹 Services,添加并实现 StoragePreference 类。

internal class StoragePreference : IStoragePreference
{
     public int Get(string key, int defaultValue) => Preferences.Get(key, defaultValue);
     public void Set(string key, int value) => Preferences.Set(key, value);
}

中间库项目 DailyPoetryM.Library 定义了接口 IStoragePreference,在被测试 Maui 项目 DailyPoetryM 中实现。
在被测试项目中添加类 ServiceLocator。资源添加和依赖注入与之前操作相同。

internal class ServiceLocator
{
    private IServiceProvider _ServiceProvider;

    public ViewModelResultPage ViewResultPage => _ServiceProvider.GetService<ViewModelResultPage>();

    public ServiceLocator()
    {
        var serviceCollection = new ServiceCollection();

        serviceCollection.AddSingleton<IStoragePoetry, StoragePoetry>();
        serviceCollection.AddSingleton<IStoragePreference, StoragePreference>();
        serviceCollection.AddSingleton<ViewModelResultPage>();

        _ServiceProvider = serviceCollection.BuildServiceProvider();
    }
}

注册接口 IStoragePoetry 的实现类为 StoragePoetry。

3.2 PageResult 设计(View 设计)

在被测试 Maui 项目 DailyPoetryM 中建立文件夹 Views,并在其中新建项 PageResult,类型为 .Net Maui ContentPage(Xaml)。
Maui 页面自动依赖注入,作为 BindingContext 的 ViewModel 自行完成依赖注入,两套系统。
希望在页面进入 PageResult 时执行命令 CommandNavigatedTo,有页面进入事件 NavigatedTo,但是没有对应命令。使用把事件转换成命令的机制。用张引老师的工具 TheSalLab.MauiBehaviors 时,出现错误提示,无法解决。

错误 XLS0502 类型“MauiActionCollection”不支持直接内容。

Nuget 安装 CommunityToolkit.Maui 支持包。将命名空间引入。

xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"

添加属性 Behaviors

<ContentPage.Behaviors>
    <toolkit:EventToCommandBehavior
        EventName="NavigatedTo"
        Command="{Binding CommandNavigatedTo}"/>
</ContentPage.Behaviors>

属性 Behaviors 是微软为控件提供的一种机制,用以扩展控件的功能。放置 ListView 用以显示诗词名字。

 <ListView ItemsSource="{Binding Poetries}">
     <ListView.ItemTemplate>
         <DataTemplate>
             <ViewCell>
                 <Label Text="{Binding Name}"/>
             </ViewCell>
         </DataTemplate>
     </ListView.ItemTemplate>
 </ListView>

在 AppShell.xaml.cs 中增加导航页面

Items.Add(new FlyoutItem
{
    Title = nameof(PageResult),
    Route = nameof(PageResult),
    Items =
    {
        new ShellContent
        {
            ContentTemplate = new DataTemplate(typeof(PageResult))
        }
    }
});  

在 AppShell.xaml 中修改属性,显示导航页面

Shell.FlyoutBehavior="Flyout"

运行失败,原因是变量 Where 没有赋值,为空引用。解决方案为在中间库项目 DailyPoetryM.Library 中类 ViewModelResultPage 的构造函数中添加语句,给变量 Where 赋值。

// ToDo 测试用 正式版需要删除
Where = Expression.Lambda<Func<Poetry, bool>>(Expression.Constant(true), Expression.Parameter(typeof(Poetry), "p"));

运行仍然失败,原因是 storagePoetry 没有进行初始化,由于初始化函数 InitializeAsync() 是异步函数,不能在构造函数中完成初始化,未解决。

4 其他内容

4.1 xmlns 引入格式

xmlns:b="clr-namespace:TheSalLab.MauiBehaviors;assembly=TheSalLab.MauiBehaviors"

表示组件 TheSalLab.MauiBehaviors 的命名空间 TheSalLab.MauiBehaviors 被标识为 b。

4.2 命名规范

https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/general-naming-conventions

4.3 问题

程序调试时出现问题

Error: Converter failed to convert value of type 'Windows.Foundation.IReference`1<Microsoft.UI.Xaml.GridLength>' to type 'Double'; BindingExpression: Path='TemplateSettings.CompactPaneGridLength' DataItem='Microsoft.UI.Xaml.Controls.SplitView'; target element is 'Microsoft.UI.Xaml.Media.Animation.SplineDoubleKeyFrame' (Name='null'); target property is 'Value' (type 'Double'). 

该问题不出现于视频中,可能是由于.net 版本造成的(视频用.net6.0 ,目前实际版本是.net8.0),网上有相关问题说明。但是并没有解决问题。

9392
9384

4.4 问题解决

问题是由于 .net 8.0 对 Flyout 支持的问题造成,为了解决问题将版本退回 .net 7.0,节 4.3 的问题解决了。
StoragePoetry 没有初始化的问题,虽然初始化函数不能加到构造函数里,但是可以加到函数 CommandNaviagedToFunction 内。

public async Task CommandNaviagedToFunction()
{
    await _StoragePoetry.InitializeAsync();
    Poetries.Clear();
    await Poetries.LoadMoreAsync();
}

问题解决,可以正常获得页面内诗词的名字。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sleevefisher

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值