将SQLite注入MAUI ViewModel时出现无参构造函数报错
问题
我是MAUI新手,现有一个基于SQLite存储的正常运行项目。尝试将数据库访问对象注入Content Page的ViewModel时,出现如下报错:
/Users/RemoteCommand/Projects/Notes/Views/AllNotesPage.xaml(9,9): Error: XLS0507: Type 'AllNotes' is not usable as an object element because it is not public or does not define a public parameterless constructor or a type converter. (Notes) IntelliSense
此前直接实例化数据库访问对象可正常运行,改为构造函数注入后出现该问题。已在MauiProgram中注册AllNotes、AllNotesPage和NotesDatabase为单例服务,也尝试过改为Transient,问题仍未解决。
相关代码
AllNotesPage.xaml
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:models="clr-namespace:Notes.Models" x:Class="Notes.Views.AllNotesPage" Title="AllNotesPage"> <ContentPage.BindingContext> <models:AllNotes /> </ContentPage.BindingContext> <ContentPage.ToolbarItems> <!--<ToolbarItem Text="Add" Clicked="Add_Clicked" IconImageSource="{FontImage Glyph='+', Color=White, Size=22}"/>--> <ToolbarItem Text="Add" Command="{Binding AddClickedCommand}" IconImageSource="{FontImage Glyph='+', Color=White, Size=22}"/> </ContentPage.ToolbarItems> <CollectionView x:Name="notesCollection" ItemsSource="{Binding Notes}" Margin="20" SelectionMode="Single" SelectionChanged="notesCollection_SelectionChanged"> <CollectionView.ItemsLayout> <LinearItemsLayout Orientation="Vertical" ItemSpacing="10"/> </CollectionView.ItemsLayout> <CollectionView.ItemTemplate> <DataTemplate> <StackLayout> <Label Text="{Binding Text}" FontSize = "22"/> <Label Text="{Binding Date}" FontSize="14" TextColor="Silver"/> </StackLayout> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </ContentPage>
AllNotesPage.xaml.cs
namespace Notes.Views; using Notes.Models; using Notes.Views; using Notes.Data; using CommunityToolkit.Mvvm.Input; public partial class AllNotesPage : ContentPage { public AllNotesPage() { InitializeComponent(); } async void notesCollection_SelectionChanged(System.Object sender, Microsoft.Maui.Controls.SelectionChangedEventArgs e) { if(e.CurrentSelection.Count != 0) { var note = (Note)e.CurrentSelection[0]; await Shell.Current.GoToAsync($"{nameof(NotePage)}?{nameof(NotePage.ItemId)}={note.ID}"); } } }
AllNotes.cs(ViewModel)
using System; using System.Collections.ObjectModel; using Notes.Data; using Notes.Views; using CommunityToolkit.Mvvm; using CommunityToolkit.Mvvm.Input; namespace Notes.Models; public partial class AllNotes { NotesDatabase _notesDatabase; public ObservableCollection<Note> Notes { get; set; } = new ObservableCollection<Note>(); public AllNotes(NotesDatabase notesDatabase) { _notesDatabase = notesDatabase; LoadNotes(); } [RelayCommand] async void AddClicked() { await Shell.Current.GoToAsync(nameof(NotePage)); } public async void LoadNotes() { Notes.Clear(); List<Note> notes = await _notesDatabase.GetItemsAsync(); foreach(Note note in notes) { Notes.Add(note); } } }
MauiProgram.cs
using Microsoft.Extensions.Logging; using Notes.Views; using Notes.Models; using Notes.Data; namespace Notes; public static class MauiProgram { public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }); #if DEBUG builder.Logging.AddDebug(); #endif builder.Services.AddSingleton<AllNotes>(); builder.Services.AddSingleton<AllNotesPage>(); builder.Services.AddSingleton<NotesDatabase>(); return builder.Build(); } }
解决方法
报错核心原因:你在XAML中直接实例化AllNotes,但该ViewModel只有带参数的构造函数,XAML无法创建需要依赖注入的对象实例。按以下步骤修改:
删除XAML中的硬编码BindingContext
移除XAML里这段代码:<ContentPage.BindingContext> <models:AllNotes /> </ContentPage.BindingContext>通过构造函数注入ViewModel到页面
修改AllNotesPage的后台代码,注入AllNotes并设置为BindingContext:namespace Notes.Views; using Notes.Models; using Notes.Data; using CommunityToolkit.Mvvm.Input; public partial class AllNotesPage : ContentPage { public AllNotesPage(AllNotes viewModel) { InitializeComponent(); BindingContext = viewModel; } async void notesCollection_SelectionChanged(System.Object sender, Microsoft.Maui.Controls.SelectionChangedEventArgs e) { if(e.CurrentSelection.Count != 0) { var note = (Note)e.CurrentSelection[0]; await Shell.Current.GoToAsync($"{nameof(NotePage)}?{nameof(NotePage.ItemId)}={note.ID}"); } } }保持服务注册不变
你已在MauiProgram中正确注册了所有服务,无需修改:builder.Services.AddSingleton<AllNotes>(); builder.Services.AddSingleton<AllNotesPage>(); builder.Services.AddSingleton<NotesDatabase>();
修改后,MAUI的依赖注入系统会自动处理对象创建和依赖注入,问题即可解决。
内容的提问来源于stack exchange,提问作者David Pugh

