Search code examples
c#mvvmdata-bindingmaui

Unable to access observable property in viewmodel from corresponding view .xaml file - .NET MAUI MVVM


I am developing a .NET MAUI application where I am using the MVVM pattern via Community.Toolkit.MVVM nuget package. In the below code, on the MorePage I am trying to bind the title to Forecast.Name, which is an obervable property of the MorePageViewModel which is set as the binding context for the MorePage itself. I have verified that the navigating function gets executed with the right object being passed around, so the problem seems to be either in the MorePageViewModel or MorePage.xaml(.cs), but I am not sure where.

namespace forecAstIng.Model
{
    public abstract class TimeSeriesData
    {
        public string Name { get; set; }
        public char MeasurementUnit { get; set; }

        public double HourTimeInterval { get; set; } = 24;
        public double DayTimeInterval => HourTimeInterval / 24;
        public double MinuteTimeInterval => HourTimeInterval * 60;

        public List<double> ValueHistory { get; set; }
        public List<double> ValuePredictions { get; set; }

        public double HistoryHigh { get; set; }
        public double HistoryLow { get; set; }

        public string CurrentBehaviour { get; set; }
        public double CurrentValue { get; set; }
    }

    class WeatherData : TimeSeriesData
    {
    }

    class StockData : TimeSeriesData
    {
    }
}
using forecAstIng.View;

namespace forecAstIng.ViewModel
{
    public partial class ForecastsViewModel : BaseViewModel
    {
        public ObservableCollection<TimeSeriesData> Forecasts { get; } = new();

        public ForecastsViewModel()
        {
            Title = "forecAstIng";
            Forecasts.Add(new WeatherData { Name = "Prague, CZ", CurrentBehaviour = "sunny", CurrentValue = 23.8776575, HistoryHigh = 27.389, HistoryLow = 20, MeasurementUnit = 'C' });
        }

        [RelayCommand]
        async Task GoToMorePage(TimeSeriesData forecast)
        {
            if (forecast is null)
                return;

            await Shell.Current.GoToAsync(nameof(MorePage), true, new Dictionary<string, object>
                {
                    {"Forecast", forecast}
                });
        }
    }
}
namespace forecAstIng.ViewModel
{
    [QueryProperty(nameof(TimeSeriesData), "Forecast")]
    public partial class MorePageViewModel : BaseViewModel
    {
        public MorePageViewModel()
        {
        }

        [ObservableProperty]
        TimeSeriesData forecast;
    } 
}
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:Class="forecAstIng.View.MorePage"
             xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:model="clr-namespace:forecAstIng.Model"
             xmlns:viewmodel="clr-namespace:forecAstIng.ViewModel"
             x:DataType="viewmodel:MorePageViewModel"
             Title="{Binding Forecast.Name}"
             BackgroundColor="#402E7A">

</ContentPage>
namespace forecAstIng.View
{
    public partial class MorePage : ContentPage
    {
        public MorePage(MorePageViewModel vm)
        {
            InitializeComponent();
            BindingContext = vm;
        }
    }
}

The route is registered in AppShell and transient services added in MauiProgram.cs

The title on the MorePage is simply blank.

With no success, i tried changing the name of the property, accessibility, the name of "Forecast" that is used everywhere as the name of property in the MorePage.xaml file and navigating function, and name of the nuget package auto-generated backing field. I had the intended behaviour working once, but then I changed something and am not sure what I did differently.


Solution

  • You have a typo in your code.

    The QueryPropertyAttribute constructor expects the name of the property and the id inside the query parameters.

    So following your code you have to change nameof(TimeSeriesData) to nameof(Forecast).

    namespace forecAstIng.ViewModel
    {
        [QueryProperty( name: nameof(Forecast), queryId: "Forecast")]
        public partial class MorePageViewModel : BaseViewModel
        {
            public MorePageViewModel()
            {
            }
    
            [ObservableProperty]
            TimeSeriesData forecast;
        } 
    }