Search code examples
c#.netmaui

How to use a passed object instantly when creating a new page in .NET Maui


I'm making a shopping list app, where each item has a edit-button, to change the name of the item. So if you press the button the user goes to a new page to do change the name of the item. Method when the user presses the edit button on the item:

[RelayCommand]
async Task GoToItemEditorAsync(Item item)
{
    if (item is null)
        return;

    await Shell.Current.GoToAsync($"{nameof(ItemEditorPage)}", true,
        new Dictionary<string, object>
        {
            {"Item", item}
        });

}

It passes the item to the new page, named Item Editor. ItemEditorViewModel:

using CommunityToolkit.Mvvm.ComponentModel;
using FinalShoppingList.Model;
using CommunityToolkit.Mvvm.Input;

namespace FinalShoppingList.ViewModel
{
    [QueryProperty(nameof(Item),"Item")]
    
    public partial class ItemEditorViewModel : ObservableObject
    {
        public ItemEditorViewModel()
        {
            
            
        }

        [ObservableProperty]
        Item item;

        [ObservableProperty]
        string text;
        [RelayCommand]
        void ChangeText()
        {
            Text = Item.Name;
        }


    }
}

So what I want to achieve is that Text = Item.Name; gets called when the side gets created and not just when I call the method, because Text is binded to the entry, where the user will change the name of the Item, so it makes sense, that the old Item name is in the entry when the side gets created. When I call the method by pressing a button, everthing works like it should, but how can I do it, that the user doesn't have to press a button and it is like that from the beginning?

I already tried to put the code in the constructor, but i get a NullReferenceException because Item is null.


Solution

  • Solved the problem by using the Mvvm Messaging System like this: Sending a Message OnAppearing in the code behind ItemEditorPage.xaml.cs:

    using CommunityToolkit.Mvvm.Messaging;
    using FinalShoppingList.ViewModel;
    using FinalShoppingList.Model;
    using CommunityToolkit.Mvvm.ComponentModel;
    
    namespace FinalShoppingList.View;
    [QueryProperty(nameof(Item), "Item")]
    public partial class ItemEditorPage : ContentPage
    {
        public ItemEditorPage(ItemEditorViewModel vm)
        {
            InitializeComponent();
            BindingContext = vm;
        }
        public Item Item { get; set; }
        protected override void OnAppearing()
        {
            base.OnAppearing();
            
            SendMessage(Item.Name);
        }
        public void SendMessage(string dataToSend)
        {
    
            WeakReferenceMessenger.Default.Send(new DataMessage(dataToSend));
        }
    }
    

    And then receiving it like that in the constructor of the viewmodel ItemEditorViewModel.cs:

    namespace FinalShoppingList.ViewModel
    {
        [QueryProperty(nameof(Item),"Item")]
        
        public partial class ItemEditorViewModel : ObservableObject
        {
            public ItemEditorViewModel()
            {
    
                WeakReferenceMessenger.Default.Register<DataMessage>(this, (r, message) =>
                {
                    
                    Text = message.Value;
                });
            }