How to pass data when navigating through TabBar?

Viewed 122

To pass data beetwen viewmodels when navigating I use query parameters (IQueryAttributable), i.e.:

NavigationParameters[nameof(SomeProperty)] = SomeProperty;
await Shell.Current.GoToAsync("SomePage", NavigationParameters);

It works as it should be working, but I wish to put SomePage into a TabBar:

<TabBar>
    <ShellContent Route="SomePage"
        ContentTemplate="{DataTemplate local:SomePage}"/>
    ...
</TabBar>

Is there a way to pass data when user click/tap SomePage icon on the tab bar? Is there some event for that so I could hook up GoToAsync method? Or maybe there is another way than query to pass data beetwen viewmodels?

3 Answers

MauiProgram.cs:

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder.UseMauiApp<App>();
        builder.Services
            .AddSingleton<Page_1>
            .AddSingleton<ViewModel_1>
            .AddSingleton<Page_2>
            .AddSingleton<ViewModel_2>
            .AddSingleton<ISharedDataInterface, SharedDataInterfaceImplementation>();
        return builder.Build();
    }
}

Page_1.xaml.cs:

public partial class Page_1 : ContentPage
{
    public LogoPage(ViewModel_1 viewModel_1)
    {
        BindingContext = viewModel_1;

        InitializeComponent();
    }
}

Page_2.xaml.cs:

public partial class Page_2 : ContentPage
{
    public LogoPage(ViewModel_2 viewModel_2)
    {
        BindingContext = viewModel_2;

        InitializeComponent();
    }
}

ViewModel_1.cs:

public class ViewModel_1
{
    public ViewModel_1(ISharedDataInterface sharedDataInterfaceImplementation)
    {
        ...
    }
}

ViewModel_2.cs:

public class ViewModel_2
{
    public ViewModel_2(ISharedDataInterface sharedDataInterfaceImplementation)
    {
        ...
    }
}

If the two pages are in the same Tab,you can create a static global variable for the viewmodel in App.xaml.cs and access this variable in your different pages.

For example,we can first define a view model (e.g. TestViewModel.cs):

   public class TestViewModel: INotifyPropertyChanged
{ 

    public TestViewModel() {

        str = "123";
    }

    public  string _str;

    public  string str
    {
        get
        {
            return _str;
        }
        set
        {
            _str = value;
            OnPropertyChanged("str");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

And define a static global variable in App.xaml.cs:

 public partial class App : Application
{

    public static TestViewModel testViewModel;
    public App()
    {
        InitializeComponent();

        MainPage = new AppShell();

        testViewModel = new TestViewModel();

    }
}

Then , you can assgin the global variable for BindingContext in different pages:

   public partial class Tab1 : ContentPage
   {
    public Tab1()
    {
        InitializeComponent();

        BindingContext = App.testViewModel;

    }
   }



  public partial class Tab2 : ContentPage
{
    public Tab2()
    {
        InitializeComponent();

        BindingContext = App.testViewModel;

    }

    private void Button_Clicked(object sender, EventArgs e)
    {
        App.testViewModel.str = "Test";

    }
}

"You could also hold handles to other view models in your view model, like a common section that's shared between all your pages."

That is the advice to follow.

Suppose each tab's viewmodel has public MySharedType Shared { get; private set; },
and constructor is MyTab1ViewModel(MySharedType shared) { this.Shared = shared; }.

Then from xaml, access a shared property by: {Binding Shared.MyProperty1}.

Related