How to hide/remove Shell ToolbarItems in child page?

280 Views Asked by At

I defined some secondary ToolbarItems, that I want to see (mostly) everywhere, in the AppShell like this:

<Shell
 ...
>

    <Shell.ToolbarItems>
        <ToolbarItem Text="Test1" Order="Secondary" Priority="0" />
        <ToolbarItem Text="Test2" Order="Secondary" />
        <ToolbarItem Text="Test4" Order="Secondary" />
    </Shell.ToolbarItems>
...
</Shell>

But now, there are some pages, mostly at the end of the navigation tree, where I don't want to have these options, because they don't make sense there.

Is there a way, to remove or hide these ToolbarItems just on these individual pages?

Unfortunately, simply calling

protected override void OnAppearing()
{
    base.OnAppearing();
    Shell.Current.ToolbarItems.Clear();
}

will remove them permanently.

Any ideas to accomplish them only for the current page?

1

There are 1 best solutions below

9
On

You can create a bindable ToolBoxItem,then you can control the visibility through a view model property.

I achieved this functionality, you refer to the following code.

1.create BindableToolbarItem.cs and add BindableProperty IsVisible.

public class BindableToolbarItem: ToolbarItem 
   {
       public static readonly BindableProperty IsVisibleProperty = BindableProperty.Create(nameof(IsVisible), typeof(bool), typeof(BindableToolbarItem), true, BindingMode.TwoWay, propertyChanged: OnIsVisibleChanged);

       public bool IsVisible
       {
           get => (bool)GetValue(IsVisibleProperty);
           set => SetValue(IsVisibleProperty, value);
       }

       private static void OnIsVisibleChanged(BindableObject bindable, object oldvalue, object newvalue)
       {
           var item = bindable as BindableToolbarItem;

           if (item == null || item.Parent == null)
               return;

           //var toolbarItems = ((ContentPage)item.Parent).ToolbarItems;
           var toolbarItems = ((AppShell)item.Parent).ToolbarItems;

           if ((bool)newvalue && !toolbarItems.Contains(item))
           {
               MainThread.BeginInvokeOnMainThread(() => {
                   toolbarItems.Add(item);
               });
           }
           else if (!(bool)newvalue && toolbarItems.Contains(item))
           {
              // Device.BeginInvokeOnMainThread(() => { toolbarItems.Remove(item); });

               MainThread.BeginInvokeOnMainThread(() => {
                   toolbarItems.Remove(item);
               });
           }
       }
   }

2.create a model to save different visible variables for different ToolbarItem.

public class TestVisibleModel: INotifyPropertyChanged 
    {
        private bool _isVisibl1;
        public bool IsVisible1
        {
            set{ SetProperty(ref _isVisibl1, value);}
            get { return _isVisibl1; }
        }

        private bool _isVisibl2;
        public bool IsVisible2
        {
            set { SetProperty(ref _isVisibl2, value); }
            get { return _isVisibl2; }
        }

        private bool _isVisibl3;
        public bool IsVisible3
        {
            set { SetProperty(ref _isVisibl3, value); }
            get { return _isVisibl3; }
        }
        public TestVisibleModel() {
            IsVisible1 = true;
            IsVisible2 = true;
            IsVisible3 = true;
        }


        bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (Object.Equals(storage, value))
                return false;
            storage = value;
            OnPropertyChanged(propertyName);
            return true;
        }
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }

3.In AppShell.xaml.cs,define an instance for TestVisibleModel and bind the different variables to the IsVisible property of ToolbarItem in AppShell.xaml.

public partial class AppShell : Shell 
{

    public TestVisibleModel visibleModel { get; private set; }

    public AppShell()
    {
        InitializeComponent();
        RegisterRoutes();

        visibleModel = new TestVisibleModel();

        // Register a message in some module
        WeakReferenceMessenger.Default.Register<VisibleChangedMessage>(this, (r, m) =>
        {
            //DisplayAlert("Test", " receive...", "OK");
            visibleModel.IsVisible1 = m.Value.IsVisible1;
            visibleModel.IsVisible2 = m.Value.IsVisible2;
            visibleModel.IsVisible3 = m.Value.IsVisible3;
        });

        BindingContext = this;
        
    }

    void RegisterRoutes()
    {

    }
}

And in AppShell.xaml:

<Shell.ToolbarItems> 
    <local:BindableToolbarItem Text="Test1" Order="Secondary" Priority="0" x:Name="ToolbarItem1" IsVisible="{Binding visibleModel.IsVisible1}" />
    <local:BindableToolbarItem Text="Test2" Order="Secondary" x:Name="ToolbarItem2" IsVisible="{Binding visibleModel.IsVisible2}"/>
    <local:BindableToolbarItem Text="Test3" Order="Secondary" x:Name="ToolbarItem3" IsVisible="{Binding visibleModel.IsVisible3}"/>
</Shell.ToolbarItems>

4.In different pages, you can send message to AppShell.xaml.cs to change the value of different IsVisible variable.

 protected override void OnAppearing() 
    {
        base.OnAppearing();

        TestVisibleModel model = new TestVisibleModel();
        model.IsVisible1 = false;
        model.IsVisible2 = false;
        model.IsVisible3 = true;

        // Send a message from some other module
        WeakReferenceMessenger.Default.Send(new VisibleChangedMessage(model));

    }

The code of VisibleChangedMessage.cs

 public class VisibleChangedMessage : ValueChangedMessage<TestVisibleModel> 
{
    public VisibleChangedMessage(TestVisibleModel value) : base(value)
    {

    }
}

Note:

For how to send message, please check document: Messenger.You need to install nuget CommunityToolkit.Mvvm.