2

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");
            }
        }
    }
}
Tanaka Mawere
  • 683
  • 1
  • 9
  • 22
  • Did you put a breakpoint on the gotoasync call, and verify that pack.topicid is not null? Why is property in one place topicId instead of TopicId? – ToolmakerSteve Jun 03 '22 at 16:50
  • 2
    I believe that `ObservableProperty` attribute is supposed to turn the private field into a public property – Jason Jun 03 '22 at 17:05
  • 1
    @ToolmakerSteve Yes I did. pack.topidId is not null. and as @Jason said, ```ObservableProperty``` makes it behind the scenes – Tanaka Mawere Jun 04 '22 at 16:28
  • @TanakaMawere could you please mark my answer as accepted if it was what you needed? – Riccardo Minato Jun 06 '22 at 11:28

1 Answers1

6

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();
}
Riccardo Minato
  • 520
  • 2
  • 11
  • CommunityToolkit.Mvvm does not recognise that there is such a method – Tanaka Mawere Jun 10 '22 at 12:29
  • @TanakaMawere you need to use the latest preview version of CommunityToolkit.Mvvm (currently 8.0.0-preview4) – Riccardo Minato Jun 10 '22 at 12:36
  • Is it stable enough to include into a production application? After updating, I am noticing errors from ```[ICommand]```. RelayCommand is good enough without further edits? – Tanaka Mawere Jun 10 '22 at 12:39
  • Honestly I wouldn't use MAUI itself in a production application yet, but that's up to you. Anyway this is a very simple feature that you can verify firsthand in the autogenerated code, so it shouldn't cause any troubles. Can't guarantee for other sections of the toolkit. If you are worried about the preview, you could create `TopicId` as a classic property, without the `ObservableProperty` attribute and use the setter. – Riccardo Minato Jun 10 '22 at 12:45
  • What kind of errors? I've used `[ICommand]` without problems. – Riccardo Minato Jun 10 '22 at 12:46
  • Okay thanks. Concerning ICommand, the only Command left is RelayCommand after updating as you have instructed me. Might do the classical way now. – Tanaka Mawere Jun 10 '22 at 12:49
  • Actually with the `[ICommand]` attribute it shouldn't be necessary to choose between `Command` or `RelayCommand`. It's all autogenerated (but yes, behind the scenes it's actually using `RelayCommand`). – Riccardo Minato Jun 10 '22 at 12:54
  • [ICommand] tag exists up to version 8 preview 1, from preview 2 its 'renamed' to [RelayCommand] – Leszek Jezierski Jul 30 '22 at 17:02