You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决.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>
问题原因与解决办法

原因

  1. .NET MAUI框架在XAML中通过DataTemplate创建页面实例时,默认会调用无参构造函数,你的页面仅提供带ViewModel参数的构造函数,因此触发异常。
  2. 未在依赖注入(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 07:55:00