So I am trying to work out data binding in a ContentView with a view model. I thought this should be pretty easy since MVVM is supposed to be the thing for MAUI but maybe I am missing something. The current solution is based on Databinding issue
So I have a simple ContentView like this:
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewModel="clr-namespace:MyProject.ViewModels"
x:Name="view"
x:Class="MyProject.Components.ContentViewComponent">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="10"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="10"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="10"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="1" Grid.Column="1"
//This NEVER picks up the value of Title >> Why??
Text="{Binding VM.Title, Source={x:Reference view}}"
FontSize="24"
FontAttributes="Bold"/>
</Grid>
</ContentView>
And the Code-Behind for my simple ContentView:
using MyProject.ViewModels;
namespace MyProject.Components;
public partial class ContentViewComponent: ContentView
{
internal MyViewModel VM { get; set; }
public static readonly BindableProperty TProperty = BindableProperty.Create(nameof(T), typeof(string), typeof(MetricImperialDropdownConverter), string.Empty, propertyChanged : TitleChanged);
private static void TitleChanged(BindableObject bindable, object oldvalue, object newvalue)
{
//This fires and sets Title to T
((ContentViewComponent)bindable).VM.Title = (string)newvalue;
}
//I want to be able to set this when reusing the component
public string T
{
get => (string)GetValue(TProperty);
set => SetValue(TProperty, value);
}
public MetricImperialDropdownConverter()
{
VM = new MyViewModel();
InitializeComponent();
}
}
And then I have a ViewModel for that like this:
using System.ComponentModel;
namespace MyProject.ViewModels
{
public class MetricImperialDropdownConverterViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnProperyChanged(string propertyName) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
private string _title = string.Empty;
public string Title
{
get { return _title; }
set { _title = value; OnProperyChanged(nameof(Title)); }
}
}
And then to use this and pass in a value:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:components="clr-namespace:MyProject.Components"
x:Class="MyProject.Pages.SomePage"
x:Name="this">
<VerticalStackLayout BindingContext="{x:Reference this}">
//This works and sets T correctly
<components:ContentViewCompontent T="Here is my Title"/>
</VerticalStackLayout>
</ContentPage>
T for the component is correctly set.
On setting T, the Title property in my ViewModel, VM, is through the PropertyChanged event.
But the UI is never updated with the value for Title.
I assume it is because the UI doesn't respond to events that happen outside their own context.
But what should I do in this case?? How can I get the UI to update correctly??