.NET MAUI Pass Value from TabBar/ShellContent to Target Page

109 Views Asked by At

I have a very simple TabBar with a few ShellContent elements such as this:

 <ShellContent
    Title="Staying at Home"
    Icon="house_user_solid.png"
    ContentTemplate="{DataTemplate views:PatientEdSelectionPage}">

    <views:PatientEdSelectionPage />
</ShellContent>

The ViewModel looks like this:

namespace Lati2d.ViewMode  
{
  public partial class PatientEdViewModel : BaseViewModel
  {
      public ObservableCollection<PatientEd> PatientEds { get; } = new();
      public ObservableCollection<Lati2d.Model.Condition> Conditions { get; } = new();
      public string PatientEd { get; set; }
      public string PatientEdTypeId { get; set; }
      public Guid ConditionId { get; set; }
      public string ConditionName { get; set; }
      public Lati2d.Model.Condition SelectedCondition { get; set; }

      PatientEdService _patientEdService;
      ConditionService _conditionService;
      public PatientEdViewModel(
          PatientEdService patientEdService,
          ConditionService conditionService)
      {
          _patientEdService = patientEdService;
          _conditionService = conditionService;

          Title = "Patient Education Titles";
      }
   }
}

This all works great. I'm now trying to get a value from the ShellContent to the page. I'm happy to pass some sort of parameter or use some sort of reference from the Page, back to the 'referrer'.

I've tried the QueryParameter attribute and a few other methods I've seen, most seem to use direct navigation, but can't seem to get it to work.

1

There are 1 best solutions below

3
On BEST ANSWER

[Rewrote answer]

Instead of inlining PatientEdSelectionPage:

<ShellContent ContentTemplate="{DataTemplate local:PatientEdSelectionPage}"/>

Consider expanding it then, you can easily add properties:

<ShellContent>
    <ShellContent.ContentTemplate>
        <DataTemplate>
            <local:PatientEdSelectionPage SomeProperty="SomeValue"/>
        </DataTemplate>
    </ShellContent.ContentTemplate>
</ShellContent>

Also, you may also like to use StaticResource

    <Shell.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="patientEdSelectionTemplate">
                <local:PatientEdSelectionPage SomeProperty="SomeValue"/>
            </DataTemplate>
        </ResourceDictionary>
    </Shell.Resources>
    <!-- ... -->
    <Tab Title="PatientEdSelection">
        <ShellContent ContentTemplate="{StaticResource patientEdSelectionTemplate}"/>
    </Tab>

[Old Answer]

This answer involves passing properties throughout your entire application via a GlobalViewModel singleton.

public partial class GlobalViewModel : BaseViewModel

As you're using Dependency Injection, set it up like this:

// MauiProgram.cs
builder.Services.AddSingleton<GlobalViewModel>();
builder.Services.AddTransient<PatientEdViewModel>();

In your AppShell.xaml.cs, you can gain access to the GlobalViewModel singleton. That way, the Shell can provide values via the GlobalViewModel singleton.

public partial class AppShell : Shell
{
    public GlobalViewModel Global { get; }

    public AppShell()
    {
        InitializeComponent();
        Global = IPlatformApplication.Current.Services.GetService<GlobalViewModel>();
        BindingContext = Global;
        // set BindingContext to either this or Global.
        // Does not matter.
        // Either way, we enable `GlobalViewModel` in the Shell XAML
    }
}

Because GlobalViewModel is a singleton, you can set properties from Shell and you can consume those same properties in PatentEdViewModel. For the latter, you can configure PatentEdViewModel via dependency injection:

public PatientEdViewModel(
          PatientEdService patientEdService,
          ConditionService conditionService,
          GlobalViewModel globalViewModel)
      {
          _patientEdService = patientEdService;
          _conditionService = conditionService;
          _globalViewModel = globalViewModel;

The comment about declaring GlobalViewModel in the App BindingContext should allow access to the GlobalViewModel in your bindings, by setting Source={RelativeSource AncestorType={x:Type viewmodel:GlobalViewModel}}, but, setting it as a dependency to your individual view models works too.