File: Platform\Windows\MauiCommandBar.cs
Web Access
Project: src\src\Controls\src\Core\Controls.Core.csproj (Microsoft.Maui.Controls)
#nullable disable
using System;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Media;
using Windows.Foundation.Collections;
using WVisibility = Microsoft.UI.Xaml.Visibility;
 
namespace Microsoft.Maui.Controls.Platform
{
	public partial class MauiCommandBar : CommandBar
	{
		Microsoft.UI.Xaml.Controls.Button _moreButton;
		Microsoft.UI.Xaml.Controls.ItemsControl _primaryItemsControl;
		bool _isInValidLocation;
 
		public MauiCommandBar()
		{
			PrimaryCommands.VectorChanged += OnCommandsChanged;
			SecondaryCommands.VectorChanged += OnCommandsChanged;
			UpdateVisibility();
			WatchForContentChanges();
		}
 
		// Set by the container if the container is a valid place to show a toolbar.
		// This exists to provide consistency with the other platforms; we've got 
		// rules in place that limit toolbars to Navigation Page and to Tabbed 
		// and Flyout-Detail Pages when they're currently displaying a Navigation Page
		public bool IsInValidLocation
		{
			get { return _isInValidLocation; }
			set
			{
				_isInValidLocation = value;
				UpdateVisibility();
			}
		}
 
		protected override void OnApplyTemplate()
		{
			base.OnApplyTemplate();
 
			_moreButton = GetTemplateChild("MoreButton") as Microsoft.UI.Xaml.Controls.Button;
			_primaryItemsControl = GetTemplateChild("PrimaryItemsControl") as Microsoft.UI.Xaml.Controls.ItemsControl;
		}
 
		void OnCommandsChanged(IObservableVector<ICommandBarElement> sender, IVectorChangedEventArgs args)
		{
			UpdateVisibility();
		}
 
		void UpdateVisibility()
		{
			// Determine whether we have a title (or some other content) inside this command bar
			var frameworkElement = Content as FrameworkElement;
 
			// Apply the rules for consistency with other platforms
 
			// Not in one of the acceptable toolbar locations from the other platforms
			if (!IsInValidLocation)
			{
				// If there's no title to display (e.g., toolbarplacement is set to bottom)
				// or the title is collapsed (e.g., because it's empty)
				if (frameworkElement == null || frameworkElement.Visibility != WVisibility.Visible)
				{
					// Just collapse the whole thing
					Visibility = WVisibility.Collapsed;
					return;
				}
 
				// The title needs to be visible, but we're not allowed to show a toolbar
				// So we need to hide the toolbar items
 
				Visibility = WVisibility.Visible;
 
				if (_moreButton != null)
				{
					_moreButton.Visibility = WVisibility.Collapsed;
				}
 
				if (_primaryItemsControl != null)
				{
					_primaryItemsControl.Visibility = WVisibility.Collapsed;
				}
 
				return;
			}
 
			// We're in one of the acceptable toolbar locations from the other platforms so the normal rules apply
 
			if (_primaryItemsControl != null)
			{
				// This is normally visible by default, but it might have been collapsed by the toolbar consistency rules above
				_primaryItemsControl.Visibility = WVisibility.Visible;
			}
 
			// Are there any commands to display?
			var visibility = PrimaryCommands.Count + SecondaryCommands.Count > 0 ? WVisibility.Visible : WVisibility.Collapsed;
 
			if (_moreButton != null)
			{
				// The "..." button should only be visible if we have commands to display
				_moreButton.Visibility = visibility;
 
				// There *is* an OverflowButtonVisibility property that does more or less the same thing, 
				// but it became available in 10.0.14393.0 and we have to support 10.0.10240
			}
 
			if (frameworkElement != null && frameworkElement.Visibility != WVisibility.Collapsed)
			{
				// If there's a title to display, we have to be visible whether or not we have commands
				Visibility = WVisibility.Visible;
			}
			else
			{
				// Otherwise, visibility depends on whether we have commands
				Visibility = visibility;
			}
		}
 
		void WatchForContentChanges()
		{
			// If the content of the command bar changes while it's collapsed, we need to 
			// react and update the visibility (e.g., if the bar is placed at the bottom and
			// has no commands, then is moved to the top and now includes the title)
 
			// There's no event on CommandBar when the content changes, so we'll bind our own
			// dependency property to Content and update our visibility when it changes
			var binding = new Microsoft.UI.Xaml.Data.Binding
			{
				Source = this,
				Path = new PropertyPath(nameof(Content)),
				Mode = Microsoft.UI.Xaml.Data.BindingMode.OneWay
			};
 
			BindingOperations.SetBinding(this, s_contentChangeWatcher, binding);
		}
 
		static readonly DependencyProperty s_contentChangeWatcher =
			DependencyProperty.Register(
				"ContentChangeWatcher",
				typeof(object),
				typeof(object),
				new PropertyMetadata(null, ContentChanged));
 
		static void ContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			(d as MauiCommandBar)?.UpdateVisibility();
		}
	}
}