SqueezeOJ
SqueezeOJ

Reputation: 527

How to handle "Parameterless Constructor" error when I need to pass a ViewModel in C# .Net MAUI?

I'm new to C# and the .NET MAUI architecture. I'm trying to use a local SQLite database for a simple voter application.

VoterListPageView is the Main Page that AppShell points to (code added below).

The following code keeps giving me this error:

System.MissingMethodException: 'No parameterless constructor defined for type 'VoterApp001.Views.VotersListPageView'.'

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);
    }
}

The problem seems to be here:

public VotersListPageView(VotersListPageViewModel viewModel)   // <-- FAILS
public VotersListPageView()      // <-- WORKS IF I COMMENT OUT OTHER RELATED LINES BELOW

I need to pass-in my ViewModel, but the error is preventing me from doing that. What am I doing wrong?

VotersListPageViewModel.cs

sing 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>

Thank you for any comments and/or suggestions!

Upvotes: 1

Views: 1840

Answers (1)

Julian
Julian

Reputation: 8934

In order to use constructor injection with MAUI Shell, you need to register all required dependencies with the MauiAppBuilder instance in your MauiProgram.cs file:

var builder = MauiApp.CreateBuilder(); 
builder 
    .UseMauiApp<App>() 
    .ConfigureFonts(fonts => 
    { 
        fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
        fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
    });

builder.Services.AddTransient<IVoterService>();
builder.Services.AddTransient<VotersListPageViewModel>();
builder.Services.AddTransient<VotersListPageView>();

You don't need to handle any of the dependency injection yourself like this, the constructor arguments are passed down by Shell automatically.

Note: You'll have to figure out yourself whether you need to register any of the classes as singletons or transients.

Gerald Verluis also wrote an answer to a similar problem here: https://stackoverflow.com/a/72433960/4308455.

James Montemagno has a great video about it on YouTube, as well: https://www.youtube.com/watch?v=xx1mve2AQr4.

Upvotes: 3

Related Questions