maui-linux/Xamarin.Forms.Platform.UAP/MasterDetailPageRenderer.cs

345 строки
8.9 KiB
C#

using System;
using System.ComponentModel;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
using Specifics = Xamarin.Forms.PlatformConfiguration.WindowsSpecific.MasterDetailPage;
namespace Xamarin.Forms.Platform.UWP
{
public class MasterDetailPageRenderer : IVisualElementRenderer, IToolbarProvider, ITitleProvider, IToolBarForegroundBinder
{
Page _master;
Page _detail;
bool _showTitle;
VisualElementTracker<Page, FrameworkElement> _tracker;
public MasterDetailControl Control { get; private set; }
public MasterDetailPage Element { get; private set; }
protected VisualElementTracker<Page, FrameworkElement> Tracker
{
get { return _tracker; }
set
{
if (_tracker == value)
return;
if (_tracker != null)
_tracker.Dispose();
_tracker = value;
}
}
public void Dispose()
{
ClearMaster();
ClearDetail();
Tracker = null;
if (Element != null)
SetElement(null);
}
Brush ITitleProvider.BarBackgroundBrush
{
set { Control.ToolbarBackground = value; }
}
Brush ITitleProvider.BarForegroundBrush
{
set { Control.ToolbarForeground = value; }
}
bool ITitleProvider.ShowTitle
{
get { return _showTitle; }
set
{
if (_showTitle == value)
return;
_showTitle = value;
Control.DetailTitleVisibility = _showTitle ? Visibility.Visible : Visibility.Collapsed;
}
}
string ITitleProvider.Title
{
get { return Element?.Title; }
set
{
if (Control != null)
Control.DetailTitle = value;
}
}
Task<CommandBar> IToolbarProvider.GetCommandBarAsync()
{
return ((IToolbarProvider)Control)?.GetCommandBarAsync();
}
FrameworkElement IVisualElementRenderer.ContainerElement
{
get { return Control; }
}
VisualElement IVisualElementRenderer.Element
{
get { return Element; }
}
#pragma warning disable 0067 // Revisit: Can't remove; required by interface
public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
#pragma warning restore
public SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
{
Size size = Device.Info.ScaledScreenSize;
return new SizeRequest(new Size(size.Width, size.Height));
}
UIElement IVisualElementRenderer.GetNativeElement()
{
return Control;
}
public void SetElement(VisualElement element)
{
MasterDetailPage old = Element;
Element = (MasterDetailPage)element;
if (element != old)
OnElementChanged(new ElementChangedEventArgs<MasterDetailPage>(old, Element));
}
protected virtual void OnElementChanged(ElementChangedEventArgs<MasterDetailPage> e)
{
if (e.OldElement != null)
e.OldElement.PropertyChanged -= OnElementPropertyChanged;
if (e.NewElement != null)
{
if (Control == null)
{
Control = new MasterDetailControl();
Control.Loaded += OnControlLoaded;
Control.Unloaded += OnControlUnloaded;
Control.SizeChanged += OnNativeSizeChanged;
Control.RegisterPropertyChangedCallback(MasterDetailControl.IsPaneOpenProperty, OnIsPaneOpenChanged);
Tracker = new VisualElementTracker<Page, FrameworkElement> { Container = Control, Element = Element };
}
e.NewElement.PropertyChanged += OnElementPropertyChanged;
UpdateMode();
UpdateDetail();
UpdateMaster();
UpdateIsPresented();
if (!string.IsNullOrEmpty(e.NewElement.AutomationId))
Control.SetValue(Windows.UI.Xaml.Automation.AutomationProperties.AutomationIdProperty, e.NewElement.AutomationId);
((ITitleProvider)this).BarBackgroundBrush = (Brush)Windows.UI.Xaml.Application.Current.Resources["SystemControlBackgroundChromeMediumLowBrush"];
UpdateToolbarPlacement();
}
}
protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == MasterDetailPage.IsPresentedProperty.PropertyName || e.PropertyName == MasterDetailPage.MasterBehaviorProperty.PropertyName)
UpdateIsPresented();
else if (e.PropertyName == "Master")
UpdateMaster();
else if (e.PropertyName == "Detail")
UpdateDetail();
else if (e.PropertyName == nameof(MasterDetailControl.ShouldShowSplitMode)
|| e.PropertyName == Specifics.CollapseStyleProperty.PropertyName
|| e.PropertyName == Specifics.CollapsedPaneWidthProperty.PropertyName)
UpdateMode();
else if(e.PropertyName == PlatformConfiguration.WindowsSpecific.Page.ToolbarPlacementProperty.PropertyName)
UpdateToolbarPlacement();
}
void ClearDetail()
{
((ITitleProvider)this).ShowTitle = false;
if (_detail == null)
return;
_detail.PropertyChanged -= OnDetailPropertyChanged;
IVisualElementRenderer renderer = Platform.GetRenderer(_detail);
renderer?.Dispose();
_detail.ClearValue(Platform.RendererProperty);
_detail = null;
}
void ClearMaster()
{
if (_master == null)
return;
_master.PropertyChanged -= OnMasterPropertyChanged;
IVisualElementRenderer renderer = Platform.GetRenderer(_master);
renderer?.Dispose();
_master.ClearValue(Platform.RendererProperty);
_master = null;
}
void OnControlLoaded(object sender, RoutedEventArgs routedEventArgs)
{
if (Element == null)
return;
Element.SendAppearing();
UpdateBounds();
}
void OnControlUnloaded(object sender, RoutedEventArgs routedEventArgs)
{
Element?.SendDisappearing();
}
void OnDetailPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == Page.TitleProperty.PropertyName || e.PropertyName == NavigationPage.CurrentPageProperty.PropertyName)
UpdateDetailTitle();
}
void OnIsPaneOpenChanged(DependencyObject sender, DependencyProperty dp)
{
((IElementController)Element).SetValueFromRenderer(MasterDetailPage.IsPresentedProperty, Control.IsPaneOpen);
UpdateBounds();
}
void OnMasterPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == Page.TitleProperty.PropertyName)
Control.MasterTitle = _master?.Title;
}
void OnNativeSizeChanged(object sender, SizeChangedEventArgs e)
{
UpdateBounds();
}
void UpdateBounds()
{
Windows.Foundation.Size masterSize = Control.MasterSize;
Windows.Foundation.Size detailSize = Control.DetailSize;
Element.MasterBounds = new Rectangle(0, 0, masterSize.Width, masterSize.Height);
Element.DetailBounds = new Rectangle(0, 0, detailSize.Width, detailSize.Height);
}
void UpdateDetail()
{
ClearDetail();
FrameworkElement element = null;
_detail = Element.Detail;
if (_detail != null)
{
_detail.PropertyChanged += OnDetailPropertyChanged;
IVisualElementRenderer renderer = _detail.GetOrCreateRenderer();
element = renderer.ContainerElement;
UpdateToolbarVisibilty();
}
Control.Detail = element;
UpdateDetailTitle();
}
void UpdateDetailTitle()
{
if (_detail == null)
return;
Control.DetailTitle = (_detail as NavigationPage)?.CurrentPage?.Title ?? _detail.Title ?? Element?.Title;
(this as ITitleProvider).ShowTitle = !string.IsNullOrEmpty(Control.DetailTitle);
}
void UpdateIsPresented()
{
// Ignore the IsPresented value being set to false for Split mode on desktop and allow the master
// view to be made initially visible
if (Device.Idiom == TargetIdiom.Desktop && Control.IsPaneOpen && Element.MasterBehavior != MasterBehavior.Popover)
return;
Control.IsPaneOpen = Element.IsPresented;
}
void UpdateMaster()
{
ClearMaster();
FrameworkElement element = null;
_master = Element.Master;
if (_master != null)
{
_master.PropertyChanged += OnMasterPropertyChanged;
IVisualElementRenderer renderer = _master.GetOrCreateRenderer();
element = renderer.ContainerElement;
}
Control.Master = element;
Control.MasterTitle = _master?.Title;
UpdateToolbarVisibilty();
}
void UpdateMode()
{
UpdateDetailTitle();
Control.CollapseStyle = Element.OnThisPlatform().GetCollapseStyle();
Control.CollapsedPaneWidth = Element.OnThisPlatform().CollapsedPaneWidth();
Control.ShouldShowSplitMode = Element.ShouldShowSplitMode;
}
void UpdateToolbarPlacement()
{
Control.ToolbarPlacement = Element.OnThisPlatform().GetToolbarPlacement();
}
void UpdateToolbarVisibilty()
{
// Enforce consistency rules on toolbar
Control.ShouldShowToolbar = _detail is NavigationPage || _master is NavigationPage;
}
public void BindForegroundColor(AppBar appBar)
{
SetAppBarForegroundBinding(appBar);
}
public void BindForegroundColor(AppBarButton button)
{
SetAppBarForegroundBinding(button);
}
void SetAppBarForegroundBinding(FrameworkElement element)
{
element.SetBinding(Windows.UI.Xaml.Controls.Control.ForegroundProperty,
new Windows.UI.Xaml.Data.Binding { Path = new PropertyPath("Control.ToolbarForeground"), Source = this, RelativeSource = new RelativeSource { Mode = RelativeSourceMode.TemplatedParent } });
}
}
}