.NET MAUI - 依赖注入 - 构造函数从未被调用
我想做一个通用的弹出框,以便在多种不同场景下重复使用。出于某种原因,尽管我已经正确注册并调用,但我的视图模型的构造函数从未被调用。
这是我在我的 MauiProgram.cs 中注册它的方式:
builder.Services.AddTransientPopup<PickerBottomSheet, BaitPickerViewModel>();
这是我的通用调用端:
public async Task<TItem?> DisplayBottomPickerAsync<TViewModel, TItem>(CancellationToken token = default)
where TViewModel : PickerBottomSheetViewModel<TItem>
where TItem : IPickableItem
{
var result = await _popup.ShowPopupAsync<TViewModel, TItem>(Shell.Current, GetOptions(true), token);
return result.WasDismissedByTappingOutsideOfPopup ? default : result.Result;
}
这是我用来调用它的代码:
var result = await _popup.DisplayBottomPickerAsync<BaitPickerViewModel, Bait>(token);
这是代码的关键部分,整组类放在一起会太冗长(按继承关系排序):
public abstract partial class PickerBottomSheetViewModel : ViewModelBase
public abstract partial class PickerBottomSheetViewModel<T> : PickerBottomSheetViewModel where T : IPickableItem
public sealed partial class BaitPickerViewModel : PickerBottomSheetViewModel<Bait>
{
private readonly SqliteStorage _sql;
private readonly ILocalizationResourceManager _lang;
public BaitPickerViewModel(PopupHost popup, SqliteStorage sql, ILocalizationResourceManager lang) : base(popup)
{
_sql = sql; //Never called
_lang = lang;
Title = _lang["SelectBaitTitle"];
AddNewText = _lang["AddNewBait"];
CanEditOrDelete = true;
}
protected override IAsyncEnumerable<Bait> LoadTypedItemsAsync(CancellationToken token) => _sql.EnumerateBaitsAsync(token);
protected override Task<Bait?> AddTypedItemAsync(CancellationToken token) => base.AddTypedItemAsync(token);
protected override Task<Bait?> EditTypedItemAsync(Bait item, CancellationToken token) => base.EditTypedItemAsync(item, token);
protected override Task DeleteTypedItemAsync(Bait item, CancellationToken token) => base.DeleteTypedItemAsync(item, token);
}
Popup 本身:
public sealed partial class PickerBottomSheet : Popup<IPickableItem>
{
public PickerBottomSheet()
{
InitializeComponent();
}
}
<mct:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:mct="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:icon="http://www.aathifmahir.com/dotnet/2022/maui/icons"
xmlns:lang="clr-namespace:LocalizationResourceManager.Maui;assembly=LocalizationResourceManager.Maui"
xmlns:common="clr-namespace:CatchLog.Common"
xmlns:models="clr-namespace:CatchLog.Models"
xmlns:viewmodels="clr-namespace:CatchLog.ViewModels.Popups"
x:Class="CatchLog.Popups.PickerBottomSheet"
x:DataType="viewmodels:PickerBottomSheetViewModel"
x:TypeArguments="models:IPickableItem"
Background="{mct:AppThemeResource Surface}"
HorizontalOptions="Fill"
VerticalOptions="End">
我真的不知道为什么这不起作用。我没有抛出异常,弹出框也会显示。只是因为构造函数根本没有被调用,所以我所赋的值也就不存在。
编辑
如果我把 BaitPickerViewModel 直接传给 PickerBottomSheet,就能工作。但这不是一个可行的解决办法,因为那样我就不能使用其他的视图模型,这也是这套实现的核心意义所在。
另外传入 PickerBottomSheetViewModel 也不可能,因为它是抽象的。
解决方案
我找到了实现我想要的方法。
现在对于每个视图模型,我还会创建一个 PickerBottomSheet 的子类,并显式注册。
builder.Services.AddTransientPopup<BaitPickerBottomSheet, BaitPickerViewModel>();
builder.Services.AddTransientPopup<SpeciesPickerBottomSheet, SpeciesPickerViewModel>();
public partial class PickerBottomSheet : Popup<IPickableItem>
{
public PickerBottomSheet(PickerBottomSheetViewModel vm)
{
BindingContext = vm;
InitializeComponent();
}
}
public sealed partial class BaitPickerBottomSheet : PickerBottomSheet
{
public BaitPickerBottomSheet(BaitPickerViewModel vm) : base(vm) { }
}
我先把它标记为答案,如果有人有更好的办法,欢迎分享 :)
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。