简体   繁体   中英

Xamarin Hiding and showing Flyout Item based on value

I am currently learning xamarin.forms bits by bits when I had this problem. I wanna make an app where a certain flyout item will be hidden if the user is not an admin. However, even after a successful login of an admin, the flyout item stays hidden. Here's the simplified version of the app.

Here's my code for AppShell.xaml:

<Shell.BindingContext>
     <viewmodel:AppShellViewModel></viewmodel:AppShellViewModel>
 </Shell.BindingContext>
 <ShellItem Route="LoginPage" FlyoutItemIsVisible="False">
     <ShellContent ContentTemplate="{DataTemplate view:LoginPage}"/>
 </ShellItem>
 <FlyoutItem Title="Page 1">
     <ShellContent Route="Page" ContentTemplate="{DataTemplate view:Page}"/>
 </FlyoutItem>
 <FlyoutItem Title="Page 2" IsVisible="{Binding isAdmin}">
     <ShellContent Route="Page2" ContentTemplate="{DataTemplate view:Page2}"/>
 </FlyoutItem>
 <MenuItem Text="isAdmin?" Command="{Binding checkCommand}"/>

AppShellViewModel.cs:

public class AppShellViewModel: BindableObject
 {
     public AppShellViewModel()
     {
         MessagingCenter.Subscribe<LoginViewModel>(this, message: "user", (sender) => {
             _isAdmin = false;
         });
         MessagingCenter.Subscribe<LoginViewModel>(this, message: "admin", (sender) => {
             _isAdmin = true;
         });
         checkCommand = new Command(async () => await checkAdmin());
     }
     private bool _isAdmin;
     public bool isAdmin
     {
         get { return _isAdmin; }
         set
         {
             _isAdmin = value;
             OnPropertyChanged();
         }
     }
     public ICommand checkCommand { get; }
     private async Task checkAdmin()
     {
         string str = $"isAdmin: {_isAdmin}";
         await App.Current.MainPage.DisplayAlert("Alert", str, "OK");
     }
 }

As I've said, the isAdmin will be modified through login method. if the user enter 'admin', isAdmin will be set to true and if it's 'user', false.

Here's my LoginPage.xaml:

<ContentPage.BindingContext>
     <viewmodel:LoginViewModel></viewmodel:LoginViewModel>
 </ContentPage.BindingContext>
 <ContentPage.Content>
     <StackLayout>
         <Entry Text="{Binding user}"/>
         <Button Text="Login" Command="{Binding loginCommand}"/>
     </StackLayout>
 </ContentPage.Content>

Here's my LoginViewModel.cs:

public class LoginViewModel: BindableObject
 {
     public LoginViewModel()
     {
         loginCommand = new Command(async () => await LoginFunc());
     }
     public ICommand loginCommand { get; }
     string _user;
     public string user
     {
         get => _user;
         set
         {
             _user = value;
             OnPropertyChanged();
         }
     }
    
     private async Task LoginFunc()
     {
         if(_user != null)
         {
             MessagingCenter.Send<LoginViewModel>(this, _user);
             await Shell.Current.GoToAsync($"//{nameof(Page)}");
         }
     }
 }

As per code above, I manage (correct me if my method is wrong) to modify the isAdmin by using MessagingCenter , which can be shown if I click the "isAdmin?" MenuItem.

I don't know if the isVisible is working even after the isAdmin property is change (when i tried to initialize isAdmin = true , the flyout item keeps showing even if the user is not an admin).

I would be grateful for any help/tips I will receive. Thank you in advance

The reason it's not working is that you are not updating the Property but the Field which leads to OnPropertyChanged being never called and hence your UI is never updated.

 public AppShellViewModel()
 {
     MessagingCenter.Subscribe<LoginViewModel>(this, message: "user", (sender) => {
         isAdmin = false;
     });
     MessagingCenter.Subscribe<LoginViewModel>(this, message: "admin", (sender) => {
         isAdmin = true;
     });
     checkCommand = new Command(async () => await checkAdmin());
 }

Good luck!

Just wanna share that I've just solve this problem. This is how:

  1. I removed the AppShellViewModel.cs completely and put its content in the AppShell.xaml.cs (the code behind)

  2. Instead of using MessagingCenter, I just used the following (code is included in the login function)

if(_user == "admin")
{
(Shell.Current as AppShell).isAdmin = true;
}
else
{
(Shell.Current as AppShell).isAdmin = false;
}

However, I'm still looking for other solutions so that I can separate the AppShell view and its viewmodel. So if you have others solutions, kindly post it here ^_^. Thank you

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM