如何解决.NET MAUI传递ViewModel时的无参构造函数错误
问题描述
我是C#和.NET MAUI新手,开发选民应用时使用本地SQLite数据库。AppShell指定主页面为VotersListPageView,但运行时抛出如下错误:
System.MissingMethodException: 'No parameterless constructor defined for type 'VoterApp001.Views.VotersListPageView'.'
当前VotersListPageView使用带VotersListPageViewModel参数的构造函数时运行失败,改用无参构造函数可正常运行,但我需要通过依赖注入传入ViewModel,想知道问题原因及解决办法。
相关代码
VotersListPageView.xaml.cs
using VoterApp001.ViewModels; namespace VoterApp001.Views; public partial class VotersListPageView : ContentPage { private VotersListPageViewModel _viewModel; public VotersListPageView(VotersListPageViewModel viewModel) // <-- FAILS //public VotersListPageView() // <-- WORKS IF I COMMENT OUT RELATED LINES BELOW { InitializeComponent(); _viewModel = viewModel; this.BindingContext = _viewModel; } protected override void OnAppearing() { base.OnAppearing(); _viewModel.GetVotersListCommand.Execute(null); } }
VotersListPageViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using System.Collections.ObjectModel; using VoterApp001; using VoterApp001.Models; using VoterApp001.Services; using VoterApp001.Views; namespace VoterApp001.ViewModels { public partial class VotersListPageViewModel : ObservableObject { public ObservableCollection<VoterModel> VotersList { get; set; } = new ObservableCollection<VoterModel>(); private readonly IVoterService _voterService; public VotersListPageViewModel(IVoterService voterService) { _voterService = voterService; } [RelayCommand] public async void GetVotersList() { VotersList.Clear(); var votersList = await _voterService.GetVotersList(); if (votersList?.Count > 0) { votersList = votersList.OrderBy(f => f.FullName).ToList(); foreach (var voter in votersList) { votersList.Add(voter); } } } } }
AppShell.xaml
<?xml version="1.0" encoding="UTF-8" ?> <Shell x:Class="VoterApp001.AppShell" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:VoterApp001" xmlns:views="clr-namespace:VoterApp001.Views" Shell.FlyoutBehavior="Disabled"> <ShellContent Title="Home" ContentTemplate="{DataTemplate views:VotersListPageView}" Route="MainPage" /> </Shell>
问题原因与解决办法
原因
- .NET MAUI框架在XAML中通过
DataTemplate创建页面实例时,默认会调用无参构造函数,你的页面仅提供带ViewModel参数的构造函数,因此触发异常。 - 未在依赖注入(DI)容器中注册ViewModel和服务,导致框架无法自动解析构造函数所需的参数。
解决步骤
1. 注册依赖注入服务
在MauiProgram.cs中,添加ViewModel和服务的注册代码,让DI容器能够解析它们:
var builder = MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); }); // 注册服务实现(替换为你的实际Service类) builder.Services.AddSingleton<IVoterService, VoterService>(); // 注册ViewModel和页面 builder.Services.AddTransient<VotersListPageViewModel>(); builder.Services.AddTransient<VotersListPageView>(); return builder.Build();
2. 调整页面构造函数(可选但推荐)
保留带参数的构造函数供DI使用,同时添加无参构造函数以支持XAML设计预览:
public partial class VotersListPageView : ContentPage { private VotersListPageViewModel _viewModel; // 供DI使用的构造函数 public VotersListPageView(VotersListPageViewModel viewModel) { InitializeComponent(); _viewModel = viewModel; BindingContext = _viewModel; } // 设计时预览用的无参构造函数(可选) public VotersListPageView() { InitializeComponent(); // 可创建模拟服务用于设计预览 _viewModel = new VotersListPageViewModel(new MockVoterService()); BindingContext = _viewModel; } protected override void OnAppearing() { base.OnAppearing(); _viewModel.GetVotersListCommand.Execute(null); } }
3. 修改AppShell的页面加载方式
避免在XAML的DataTemplate中直接引用页面类型,改为通过DI注入页面实例:
修改AppShell.xaml
<?xml version="1.0" encoding="UTF-8" ?> <Shell x:Class="VoterApp001.AppShell" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:VoterApp001" Shell.FlyoutBehavior="Disabled"> </Shell>
修改AppShell.xaml.cs
通过构造函数注入页面实例并添加到Shell:
public partial class AppShell : Shell { public AppShell(VotersListPageView mainPage) { InitializeComponent(); Items.Add(new ShellContent { Content = mainPage, Title = "Home", Route = "MainPage" }); } }
4. 修复ViewModel中的逻辑错误
你的GetVotersList方法存在无限循环问题(遍历列表时向自身添加元素),改为向VotersList添加:
[RelayCommand] public async void GetVotersList() { VotersList.Clear(); var votersList = await _voterService.GetVotersList(); if (votersList?.Count > 0) { var sortedVoters = votersList.OrderBy(f => f.FullName).ToList(); foreach (var voter in sortedVoters) { VotersList.Add(voter); } } }
内容的提问来源于stack exchange,提问作者SqueezeOJ
相关产品推荐
相关产品推荐

