Search code examples
maui.net-maui

Passing parameter from ViewModel to ViewModel in .NET MAUI using CommunityToolkit.MVVM


My receiving Viewmodel (QuestionsPageViewModel) is not receiving the TopidId after passing it through Shell navigation as shown in the code below. I have placed the breakpoint at the LoadQuestions method in the QuestionsPageViewModel. When it is called, TopicId is null. What am I missing?

HomePageViewModel

//This is in a command executed after clicking a button. And this is working fine
await Shell.Current.GoToAsync($"{nameof(QuestionsPage)}?TopicId={pack.TopicId}");

QuestionsPageViewModel

[INotifyPropertyChanged]
[QueryProperty(nameof(TopicId), nameof(TopicId))]
    public partial class QuestionsPageViewModel
    {
        public ObservableRangeCollection<Question> QuestionsList { get; set; } = new();
        [ObservableProperty]
        string? title;

        [ObservableProperty]
        public string topicId;

        public QuestionsPageViewModel()
        {
            LoadQuestions();
        }

        async void LoadQuestions()
        {
            Title = Utilities.ConvertTopicIdToString(short.Parse(TopicId));

            try
            {
                using (var context = new DataContext())
                {
                    QuestionPack questionPack = context.QuestionPacks
                        .First(x => x.TopicId == short.Parse(TopicId));

                    var questions = JsonConvert.DeserializeObject<List<Question>>(questionPack.Questions);
                    QuestionsList.AddRange(questions);
                }

            }
            catch (Exception ex)
            {
                await Shell.Current.DisplayAlert("Error", $"Something went wrong: {ex}", "Cancel");
            }
        }
    }
}

Solution

  • First of all, your field topicId should be private. CommumityToolkit.Mvvm will generate for you the public property.

    Secondly, topicId is null because you're checking its value in a function called in the constructor. While you're executing the constructor, the shell navigation parameters are not initialized yet.

    If you want to be sure that LoadQuestions() will be called after topicId is initialized, CommumityToolkit.Mvvm since version 8.0.0 should generate a partial method that can be used to execute some code after an ObservableProperty changes its value. In your case the name of this method should be OnTopicIdChanged(string value).

    Try adding in your viewmodel this method and remove the function call from the constructor:

    partial void OnTopicIdChanged(string value)
    {
        LoadQuestions();
    }