.NET MAUI: passed object can't be accessed until after the XAML runs

89 views Asked by At

The Problem

I have an object that I'm passing from ViewModel A to ViewModel B. The object has properties that are used in the XAML. The problem is that I don't have access to the passed object until after the XAML runs.

Here's what I'd like to happen:
enter image description here

My Current Code

Here's my ViewModel. Note the Appearing method is is an EventToCommandBehavior method and runs before the XAML runs. Also note that if I put the code that's in Appearing into the ViewModel's constructor I get the same behavior: if I put a break point on the first line of the Appearing method, Object.FirstName is null.

[QueryProperty("Object","Object")]
public partial class ViewModel: ObservableObject
{
  [ObservableProperty] private Object object;
  [ObservableProperty] private string firstName;
  [ObservableProperty] private string lastName;
  [ObservableProperty] private string someOtherString;

  [RelayCommand]
  private async Task Appearing()
  {
     FirstName = Object.FirstName;
     LastName = Object.LastNamel
     SomeOtherString = Object.SomeOtherString;
  }

  // NOTE: WE COULD USE THE CONSTRUCTOR INSTEAD OF 'APPEARING' AND 
  // GET THE SAME RESULTS
  //public ViewModel()
  //{
  //   FirstName = Object.FirstName;
  //   LastName = Object.LastNamel
  //   SomeOtherString = Object.SomeOtherString;
  //}

Here's the XAML that DOESN'T get populated:

<ContentPage>
    <ContentPage.Behaviors>
        <toolkit:EventToCommandBehavior Command="{Binding AppearingCommand}"
                                        EventName="Appearing" />

    <Grid>
        <Label Text="{Binding FirstName}"/>
        <Label Text="{Binding LastName}"/>
        <Label Text="{Binding SomeOtherString}"/>
    </Grid>
</ContentPage>

The Object is passed correctly

I do eventually get access to the passed object. For example, if I do this the labels get populated, but it's too little too late. If I put a break point over the first line in TooLittleTooLate(), the Object.FirstNAme is populated with the passed value.

[QueryProperty("Object","Object")]
public partial class ViewModel: ObservableObject
{
  [ObservableProperty] private Object object;
  [ObservableProperty] private string firstName;
  [ObservableProperty] private string lastName;
  [ObservableProperty] private string someOtherString;

  [RelayCommand]
  private async TooLittleTooLate()
  {
     FirstName = Object.FirstName;
     LastName = Object.LastNamel
     SomeOtherString = Object.SomeOtherString;
  }
}

Along with this xaml:

<ContentPage>
    <Grid>
        <Label Text="{Binding FirstName}"/>
        <Label Text="{Binding LastName}"/>
        <Label Text="{Binding SomeOtherString}"/>
        <Button Text="Press Me" 
                Command={Binding TooLittleTooLateCommand}/>
    </Grid>
</ContentPage>

When I do this and the user presses the button, the labels get populated, but that's too late! I need the labels to be populated before the XAML runs for the first time.

I think I'm missing something really obvious, because I've done stuff like this before with no issues.

EDIT: Solution

Yep, the problem was obvious. Instead of binding to the property, I should have bound to the Object.Property.

Instead of this:

Label Text={Binding FirstName}/>

It should've been this:

Label Text={Binding Object.FirstName}/>

I'm not feeling too intelligent right now.

1

There are 1 answers

0
Guangyu Bai - MSFT On

Just as Jason said that You should be able to bind directly to Object and when Object is set it will fire a PropertyChanged and update the UI.

Here is the code you can refer to:

<ContentPage>
    <Grid>
        <Label Text="{Binding Object.FirstName}"/>
        <Label Text="{Binding Object.LastName}"/>
        <Label Text="{Binding Object.SomeOtherString}"/>
        <Button Text="Press Me" 
                Command={Binding TooLittleTooLateCommand}/>
    </Grid>
</ContentPage>