Nejox
Nejox

Reputation: 41

NET 8 MAUI change Visibilty TabBar Item in ViewModel

I use MVVM for my App and want to achive to change the visibility of my TabBarItems after i presed a Login Button. But I dont know what the best practice is.

I have a TabBar in my AppShell which looked like this

   <ShellContent
           Title="Tab1"
           Icon="tab1.svg"
           ContentTemplate="{DataTemplate local:TabOneView}"
           Route="TabOne">
   </ShellContent>

   <ShellContent
           Title="Login"
           Icon="login.svg"
           IsVisible="{Binding LoginIsVisible}"
           ContentTemplate="{DataTemplate local:LoginView}"
           Route="Login">
   </ShellContent>

   <ShellContent
           Title="Tab3"
           Icon="Tab3.svg"
           IsVisible="{Binding Tab3IsVisible}"
           ContentTemplate="{DataTemplate local:TabThreeView}"
           Route="TabThree">
   </ShellContent>

Tab3 should not be visible at the start. And the LoginTab should be visible. Should I assign the visibility in the code behind from the AppShell or is there a better way for MVVM?

Now I have the View and ViewModel for for my Login

<VerticalStackLayout>

    <Button 
        Margin="0,20,0,0"
        BackgroundColor="#0074BA" 
        HeightRequest="60" Text="Login" 
        TextColor="White" Command="{Binding LoginCommand}">
      <Button.Triggers>
        <Trigger TargetType="Button" Property="IsFocused" Value="True">
          <Setter Property="BackgroundColor" Value="Grey"/>
        </Trigger>
      </Button.Triggers>
    </Button>

</VerticalStackLayout>

namespace MyApp.ViewModels
{
  public partial class LoginViewModel : BaseViewModel
  {
    [ObservableProperty]
    [NotifyCanExecuteChangedFor(nameof(LoginCommand))]
    public string? user;

    public LoginViewModel()
    {
    }

    private bool CanLogin(object obj)
    {
        return User!= null 
            && User!= string.Empty;
    }

    [RelayCommand(CanExecute = nameof(CanLogin))]
    private async Task Login(object obj)
    {
    }
 }
}

Now when I press the Login button the LoginView should not be visible and the Tab3 should be. Hope you can give me some advice. Thanks :-)

Upvotes: 0

Views: 184

Answers (2)

Nejox
Nejox

Reputation: 41

I have now a different approach. After I clicked the Login Button I load the AppShell again with different visibility settings.

In my LoginViewModel

    [RelayCommand(CanExecute = nameof(CanLogin))]
     private async Task Login(object obj)
     {
         await Task.Run(() =>
         {
             if (Application.Current != null)
             {
                 // Reload the AppShell
                 Application.Current.MainPage = new AppShell(new AppShellViewModel(true));
             }
         });
     }

In my AppShellViewModel

public AppShellViewModel(bool login)
    {
        // Check if user made a login
        if (login)
        {
            // Set Visibility Propertys
        }      
    }

Upvotes: 0

Jianwei Sun - MSFT
Jianwei Sun - MSFT

Reputation: 4302

You can refer to this following code:

Create MAUI project and then add LoginPage and NewPage1 to root directory, also ViewModels folder within LoginViewModel:

enter image description here

LoginPage like this:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp5.LoginPage"
             Title="LoginPage">

    <VerticalStackLayout>
        <Label
            Text="Welcome to .NET MAUI!"
            VerticalOptions="Center"
            HorizontalOptions="Center" />
        <Button Text="Login"  
                Command="{Binding LoginCommand}"/>
    </VerticalStackLayout>
</ContentPage>
public partial class LoginPage : ContentPage
{
    public LoginPage()
    {
        InitializeComponent();
        this.BindingContext = new LoginViewModel();
    }
}

LoginViewModel:

public class LoginViewModel
{
    public Command LoginCommand { get; }

    public LoginViewModel () { LoginCommand = new Command (OnLoginClicked); }

    private async void OnLoginClicked (object obj)
    {
         // Do some judgment to see if it is compatible with the login
         //...

         await Shell.Current.GoToAsync ($"//{nameof(MainPage)}");
    }
}

Add a button to MainPage for returning to LoginPage:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp5.MainPage">

   <ScrollView>
        <VerticalStackLayout
            Spacing="25"
            Padding="30,0"
            VerticalOptions="Center">

           .....

           <Button Text="LoginPage" Clicked="Button_Clicked"/>

       </VerticalStackLayout>
    </ScrollView>

</ContentPage>
public partial class MainPage: ContentPage 
{
  int count = 0;

  public MainPage() 
  {
    InitializeComponent();
  }
  
  ....
  
  private void Button_Clicked(object sender, EventArgs e) 
  {
    Shell.Current.GoToAsync($"//{nameof(LoginPage)}");
  }
}

AppShell.xaml:

<Shell
    x:Class="MauiApp5.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:MauiApp5"
    Shell.FlyoutBehavior="Disabled">


   <ShellContent Title="LoginPage" Route="LoginPage" ContentTemplate="{DataTemplate local:LoginPage}" Shell.TabBarIsVisible="False"/>
    
    <FlyoutItem >
        <ShellContent Title="Home" Route="MainPage" ContentTemplate="{DataTemplate local:MainPage}" />
        <ShellContent Title="NewPage1" Route="NewPage1" ContentTemplate="{DataTemplate local:NewPage1}" />
    </FlyoutItem>

</Shell>

Here is the effect.

Upvotes: 0

Related Questions