File: Handlers\Shell\Windows\ShellFlyoutItemView.cs
Web Access
Project: src\src\Controls\src\Core\Controls.Core.csproj (Microsoft.Maui.Controls)
#nullable disable
using System.ComponentModel;
using Microsoft.Maui.Graphics;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using WRect = Windows.Foundation.Rect;
using WVisibility = Microsoft.UI.Xaml.Visibility;
 
namespace Microsoft.Maui.Controls.Platform
{
	public partial class ShellFlyoutItemView : ContentControl
	{
		public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register(
			nameof(IsSelected), typeof(bool), typeof(ShellFlyoutItemView),
			new PropertyMetadata(default(bool), IsSelectedChanged));
 
		View _content;
		object _previousDataContext;
		Shell _shell;
		ShellView ShellView => _shell.Handler?.PlatformView as ShellView;
 
		public ShellFlyoutItemView()
		{
			this.DataContextChanged += OnDataContextChanged;
		}
 
		public bool IsSelected
		{
			get => (bool)GetValue(IsSelectedProperty);
			set => SetValue(IsSelectedProperty, value);
		}
 
		void OnDataContextChanged(Microsoft.UI.Xaml.FrameworkElement sender, Microsoft.UI.Xaml.DataContextChangedEventArgs args)
		{
			if (_previousDataContext == args.NewValue)
				return;
 
			_previousDataContext = args.NewValue;
			if (_content != null)
			{
				if (_content.BindingContext is INotifyPropertyChanged inpc)
					inpc.PropertyChanged -= ShellElementPropertyChanged;
 
				if (_content.Parent is BaseShellItem bsi)
					bsi.RemoveLogicalChild(_content);
				else
					_shell?.RemoveLogicalChild(_content);
 
				_content.Cleanup();
				_content.BindingContext = null;
				_content.Parent = null;
				_content = null;
			}
 
			BindableObject bo = null;
 
			if (args.NewValue is NavigationViewItemViewModel vm && vm.Data is BindableObject bindableObject)
				bo = bindableObject;
			else
				bo = (BindableObject)args.NewValue;
 
			var element = bo as Element;
			_shell = element?.FindParentOfType<Shell>();
			DataTemplate dataTemplate = (_shell as IShellController)?.GetFlyoutItemDataTemplate(bo);
 
			if (bo != null)
				bo.PropertyChanged += ShellElementPropertyChanged;
 
			if (dataTemplate != null)
			{
				_content = (View)dataTemplate.CreateContent();
 
				// Set binding context before calling AddLogicalChild so parent binding context doesn't propagate to view
				_content.BindingContext = bo;
 
				if (bo is BaseShellItem bsi)
					bsi.AddLogicalChild(_content);
				else
					_shell.AddLogicalChild(_content);
 
 
				var platformView = _content.ToPlatform(_shell.Handler.MauiContext);
 
				Content = platformView;
				UpdateVisualState();
			}
		}
 
		void ShellElementPropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			if (e.Is(BaseShellItem.IsCheckedProperty))
				UpdateVisualState();
		}
 
		protected override global::Windows.Foundation.Size MeasureOverride(global::Windows.Foundation.Size availableSize)
		{
			if (ShellView == null)
				return base.MeasureOverride(availableSize);
 
			if (!ShellView.IsPaneOpen)
				return base.MeasureOverride(availableSize);
 
			if (ShellView.OpenPaneLength < availableSize.Width)
				return base.MeasureOverride(availableSize);
 
			if (_content is IView view)
			{
				if (Parent is FrameworkElement fe)
				{
					if (!_content.IsVisible)
					{
						fe.Visibility = WVisibility.Collapsed;
					}
					else
					{
						fe.Visibility = WVisibility.Visible;
					}
				}
				base.MeasureOverride(availableSize);
				var request = view.Measure(availableSize.Width, availableSize.Height);
				Clip = new RectangleGeometry { Rect = new WRect(0, 0, request.Width, request.Height) };
				return request.ToPlatform();
			}
 
			return base.MeasureOverride(availableSize);
		}
 
		protected override global::Windows.Foundation.Size ArrangeOverride(global::Windows.Foundation.Size finalSize)
		{
			if (this.ActualWidth > 0 && _content is IView view)
			{
				view.Arrange(new Rect(0, 0, finalSize.Width, finalSize.Height));
				return finalSize;
			}
 
			return base.ArrangeOverride(finalSize);
		}
 
		void UpdateVisualState()
		{
			if (_content?.BindingContext is BaseShellItem baseShellItem && baseShellItem != null)
			{
				if (baseShellItem.IsChecked)
					VisualStateManager.GoToState(_content, "Selected");
				else
					VisualStateManager.GoToState(_content, "Normal");
			}
		}
 
		static void IsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			((ShellFlyoutItemView)d).UpdateVisualState();
		}
	}
}