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

390 строки
14 KiB
C#

using System;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
using WImageSource = Windows.UI.Xaml.Media.ImageSource;
namespace Xamarin.Forms.Platform.UWP
{
public class MasterDetailControl : Control, IToolbarProvider, ITitleViewRendererController
{
public static readonly DependencyProperty MasterProperty = DependencyProperty.Register("Master", typeof(FrameworkElement), typeof(MasterDetailControl),
new PropertyMetadata(default(FrameworkElement)));
public static readonly DependencyProperty MasterTitleProperty = DependencyProperty.Register("MasterTitle", typeof(string), typeof(MasterDetailControl), new PropertyMetadata(default(string)));
public static readonly DependencyProperty DetailProperty = DependencyProperty.Register("Detail", typeof(FrameworkElement), typeof(MasterDetailControl),
new PropertyMetadata(default(FrameworkElement)));
public static readonly DependencyProperty IsPaneOpenProperty = DependencyProperty.Register("IsPaneOpen", typeof(bool), typeof(MasterDetailControl), new PropertyMetadata(default(bool)));
public static readonly DependencyProperty ShouldShowSplitModeProperty = DependencyProperty.Register(nameof(ShouldShowSplitMode), typeof(bool), typeof(MasterDetailControl),
new PropertyMetadata(default(bool), OnShouldShowSplitModeChanged));
public static readonly DependencyProperty ShouldShowNavigationBarProperty = DependencyProperty.Register(nameof(ShouldShowNavigationBar), typeof(bool), typeof(MasterDetailControl),
new PropertyMetadata(true, OnShouldShowSplitModeChanged));
public static readonly DependencyProperty CollapseStyleProperty = DependencyProperty.Register(nameof(CollapseStyle), typeof(CollapseStyle),
typeof(MasterDetailControl), new PropertyMetadata(CollapseStyle.Full, CollapseStyleChanged));
public static readonly DependencyProperty CollapsedPaneWidthProperty = DependencyProperty.Register(nameof(CollapsedPaneWidth), typeof(double), typeof(MasterDetailControl),
new PropertyMetadata(48d, CollapsedPaneWidthChanged));
public static readonly DependencyProperty DetailTitleProperty = DependencyProperty.Register("DetailTitle", typeof(string), typeof(MasterDetailControl), new PropertyMetadata(default(string)));
public static readonly DependencyProperty DetailTitleIconProperty = DependencyProperty.Register(nameof(DetailTitleIcon), typeof(WImageSource), typeof(MasterDetailControl), new PropertyMetadata(default(WImageSource)));
public static readonly DependencyProperty DetailTitleViewProperty = DependencyProperty.Register(nameof(DetailTitleView), typeof(View), typeof(MasterDetailControl), new PropertyMetadata(default(View), OnTitleViewPropertyChanged));
public static readonly DependencyProperty ToolbarForegroundProperty = DependencyProperty.Register("ToolbarForeground", typeof(Brush), typeof(MasterDetailControl),
new PropertyMetadata(default(Brush)));
public static readonly DependencyProperty ToolbarBackgroundProperty = DependencyProperty.Register("ToolbarBackground", typeof(Brush), typeof(MasterDetailControl),
new PropertyMetadata(default(Brush)));
public static readonly DependencyProperty MasterTitleVisibilityProperty = DependencyProperty.Register("MasterTitleVisibility", typeof(Visibility), typeof(MasterDetailControl),
new PropertyMetadata(default(Visibility)));
public static readonly DependencyProperty DetailTitleVisibilityProperty = DependencyProperty.Register("DetailTitleVisibility", typeof(Visibility), typeof(MasterDetailControl),
new PropertyMetadata(default(Visibility)));
public static readonly DependencyProperty DetailTitleViewVisibilityProperty = DependencyProperty.Register(nameof(DetailTitleViewVisibility), typeof(Visibility), typeof(MasterDetailControl),
new PropertyMetadata(default(Visibility)));
public static readonly DependencyProperty MasterToolbarVisibilityProperty = DependencyProperty.Register("MasterToolbarVisibility", typeof(Visibility), typeof(MasterDetailControl),
new PropertyMetadata(default(Visibility)));
public static readonly DependencyProperty ContentTogglePaneButtonVisibilityProperty = DependencyProperty.Register(nameof(ContentTogglePaneButtonVisibility), typeof(Visibility), typeof(MasterDetailControl),
new PropertyMetadata(default(Visibility)));
CommandBar _commandBar;
readonly ToolbarPlacementHelper _toolbarPlacementHelper = new ToolbarPlacementHelper();
bool _firstLoad;
public bool ShouldShowToolbar
{
get { return _toolbarPlacementHelper.ShouldShowToolBar; }
set { _toolbarPlacementHelper.ShouldShowToolBar = value; }
}
TaskCompletionSource<CommandBar> _commandBarTcs;
FrameworkElement _masterPresenter;
FrameworkElement _detailPresenter;
SplitView _split;
ToolbarPlacement _toolbarPlacement;
bool _toolbarDynamicOverflowEnabled = true;
FrameworkElement _titleViewPresenter;
TitleViewManager _titleViewManager;
public MasterDetailControl()
{
DefaultStyleKey = typeof(MasterDetailControl);
DetailTitleVisibility = Visibility.Collapsed;
CollapseStyle = CollapseStyle.Full;
}
public FrameworkElement Detail
{
get { return (FrameworkElement)GetValue(DetailProperty); }
set { SetValue(DetailProperty, value); }
}
public Windows.Foundation.Size DetailSize
{
get
{
double height = ActualHeight;
double width = ActualWidth;
if (_commandBar != null)
height -= _commandBar.ActualHeight;
if (ShouldShowSplitMode && IsPaneOpen)
{
if (_split != null)
width -= _split.OpenPaneLength;
else if (_detailPresenter != null)
width -= _masterPresenter.ActualWidth;
}
return new Windows.Foundation.Size(Math.Max(width, 0), Math.Max(height, 0));
}
}
public string DetailTitle
{
get { return (string)GetValue(DetailTitleProperty); }
set { SetValue(DetailTitleProperty, value); }
}
public WImageSource DetailTitleIcon
{
get { return (WImageSource)GetValue(DetailTitleIconProperty); }
set { SetValue(DetailTitleIconProperty, value); }
}
public View DetailTitleView
{
get { return (View)GetValue(DetailTitleViewProperty); }
set { SetValue(DetailTitleViewProperty, value); }
}
public Visibility DetailTitleVisibility
{
get { return (Visibility)GetValue(DetailTitleVisibilityProperty); }
set { SetValue(DetailTitleVisibilityProperty, value); }
}
public Visibility DetailTitleViewVisibility
{
get { return (Visibility)GetValue(DetailTitleViewVisibilityProperty); }
set { SetValue(DetailTitleViewVisibilityProperty, value); }
}
public bool IsPaneOpen
{
get { return (bool)GetValue(IsPaneOpenProperty); }
set { SetValue(IsPaneOpenProperty, value); }
}
public FrameworkElement Master
{
get { return (FrameworkElement)GetValue(MasterProperty); }
set { SetValue(MasterProperty, value); }
}
public Windows.Foundation.Size MasterSize
{
get
{
double height = ActualHeight;
double width = 0;
// On first load, the _commandBar will still occupy space by the time this is called.
// Check ShouldShowToolbar to make sure the _commandBar will still be there on render.
if ((_firstLoad || !ShouldShowSplitMode) && _commandBar != null && ShouldShowToolbar)
{
height -= _commandBar.ActualHeight;
_firstLoad = false;
}
if (_split != null)
width = _split.OpenPaneLength;
else if (_masterPresenter != null)
width = _masterPresenter.ActualWidth;
return new Windows.Foundation.Size(Math.Max(width, 0), Math.Max(height, 0));
}
}
public string MasterTitle
{
get { return (string)GetValue(MasterTitleProperty); }
set { SetValue(MasterTitleProperty, value); }
}
public Visibility MasterTitleVisibility
{
get { return (Visibility)GetValue(MasterTitleVisibilityProperty); }
set { SetValue(MasterTitleVisibilityProperty, value); }
}
public Visibility MasterToolbarVisibility
{
get { return (Visibility)GetValue(MasterToolbarVisibilityProperty); }
set { SetValue(MasterToolbarVisibilityProperty, value); }
}
public bool ShouldShowSplitMode
{
get { return (bool)GetValue(ShouldShowSplitModeProperty); }
set { SetValue(ShouldShowSplitModeProperty, value); }
}
public CollapseStyle CollapseStyle
{
get { return (CollapseStyle)GetValue(CollapseStyleProperty); }
set { SetValue(CollapseStyleProperty, value); }
}
public ToolbarPlacement ToolbarPlacement
{
get { return _toolbarPlacement; }
set
{
_toolbarPlacement = value;
_toolbarPlacementHelper.UpdateToolbarPlacement();
}
}
public bool ToolbarDynamicOverflowEnabled
{
get { return _toolbarDynamicOverflowEnabled; }
set
{
_toolbarDynamicOverflowEnabled = value;
UpdateToolbarDynamicOverflowEnabled();
}
}
public Visibility ContentTogglePaneButtonVisibility
{
get { return (Visibility)GetValue(ContentTogglePaneButtonVisibilityProperty); }
set { SetValue(ContentTogglePaneButtonVisibilityProperty, value); }
}
public double CollapsedPaneWidth
{
get { return (double)GetValue(CollapsedPaneWidthProperty); }
set { SetValue(CollapsedPaneWidthProperty, value); }
}
public Brush ToolbarBackground
{
get { return (Brush)GetValue(ToolbarBackgroundProperty); }
set { SetValue(ToolbarBackgroundProperty, value); }
}
public Brush ToolbarForeground
{
get { return (Brush)GetValue(ToolbarForegroundProperty); }
set { SetValue(ToolbarForegroundProperty, value); }
}
public bool ShouldShowNavigationBar
{
get { return (bool)GetValue(ShouldShowNavigationBarProperty); }
set { SetValue(ShouldShowNavigationBarProperty, value); }
}
Task<CommandBar> IToolbarProvider.GetCommandBarAsync()
{
if (_commandBar != null)
return Task.FromResult(_commandBar);
_commandBarTcs = new TaskCompletionSource<CommandBar>();
ApplyTemplate();
var commandBarFromTemplate = _commandBarTcs.Task;
_commandBarTcs = null;
return commandBarFromTemplate;
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
_split = GetTemplateChild("SplitView") as SplitView;
if (_split == null)
return;
var paneToggle = GetTemplateChild("PaneTogglePane") as Windows.UI.Xaml.Controls.Button;
if (paneToggle != null)
paneToggle.Click += OnToggleClicked;
var contentToggle = GetTemplateChild("ContentTogglePane") as Windows.UI.Xaml.Controls.Button;
if (contentToggle != null)
contentToggle.Click += OnToggleClicked;
_masterPresenter = GetTemplateChild("MasterPresenter") as FrameworkElement;
_detailPresenter = GetTemplateChild("DetailPresenter") as FrameworkElement;
_titleViewPresenter = GetTemplateChild("TitleViewPresenter") as FrameworkElement;
_commandBar = GetTemplateChild("CommandBar") as CommandBar;
_toolbarPlacementHelper.Initialize(_commandBar, () => ToolbarPlacement, GetTemplateChild);
UpdateToolbarDynamicOverflowEnabled();
UpdateMode();
if (_commandBarTcs != null)
_commandBarTcs.SetResult(_commandBar);
_titleViewManager = new TitleViewManager(this);
}
static void OnShouldShowSplitModeChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
((MasterDetailControl)dependencyObject).UpdateMode();
}
static void CollapseStyleChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
((MasterDetailControl)dependencyObject).UpdateMode();
}
static void CollapsedPaneWidthChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
((MasterDetailControl)dependencyObject).UpdateMode();
}
static void OnTitleViewPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
((MasterDetailControl)dependencyObject)._titleViewManager?.OnTitleViewPropertyChanged();
}
void OnToggleClicked(object sender, RoutedEventArgs args)
{
IsPaneOpen = !IsPaneOpen;
}
void UpdateMode()
{
if (_split == null)
{
return;
}
_split.DisplayMode = ShouldShowSplitMode
? SplitViewDisplayMode.Inline
: CollapseStyle == CollapseStyle.Full ? SplitViewDisplayMode.Overlay : SplitViewDisplayMode.CompactOverlay;
_split.CompactPaneLength = CollapsedPaneWidth;
if (_split.DisplayMode == SplitViewDisplayMode.Inline)
{
// If we've determined that the pane will always be open, then there's no
// reason to display the show/hide pane button in the master
MasterToolbarVisibility = Visibility.Collapsed;
}
// If we're in compact mode or the pane is always open,
// we don't need to display the content pane's toggle button
ContentTogglePaneButtonVisibility = _split.DisplayMode == SplitViewDisplayMode.Overlay
? Visibility.Visible
: Visibility.Collapsed;
if (ContentTogglePaneButtonVisibility == Visibility.Visible)
DetailTitleVisibility = Visibility.Visible;
if (DetailTitleVisibility == Visibility.Visible && !ShouldShowNavigationBar)
DetailTitleVisibility = Visibility.Collapsed;
_firstLoad = true;
}
View ITitleViewRendererController.TitleView => DetailTitleView;
FrameworkElement ITitleViewRendererController.TitleViewPresenter => _titleViewPresenter;
Visibility ITitleViewRendererController.TitleViewVisibility
{
get => DetailTitleViewVisibility;
set => DetailTitleViewVisibility = value;
}
CommandBar ITitleViewRendererController.CommandBar { get => _commandBar; }
void UpdateToolbarDynamicOverflowEnabled()
{
if (_commandBar != null)
{
_commandBar.IsDynamicOverflowEnabled = ToolbarDynamicOverflowEnabled;
}
}
}
}