maui-linux/Xamarin.Forms.Core/Page.cs

410 строки
12 KiB
C#
Исходник Обычный вид История

2016-03-22 23:02:25 +03:00
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Xamarin.Forms.Internals;
2016-03-22 23:02:25 +03:00
using Xamarin.Forms.Platform;
namespace Xamarin.Forms
{
[RenderWith(typeof(_PageRenderer))]
Platform Specifics (#301) * Playing around with how the platform specifics interfaces etc. might work * Sample implementation of iOS navigation translucency * Very slightly reduced code * Better vendor stuff * Drop single-implemenation interfaces * Generics on NavigationPage * On-demand vendor stuff * Remove functionally duplicate classes and make ControlGallery work again * Namespace all the things. XAML test. * Can use Effect to attach platform specific * Attach Effect on PropertyChanging for XAML support! * Rename IConfigPlatform interfaces for readability * Some renaming to match the documents * Split class files * Clear out test-only code * Re-namespace * Added On method to rendered Elements * Allow for removal of platform suffix, convenience methods on specific platforms * Creating a gallery page for specifics * Add rudimentary Platform Specifics gallery; make CollapseStyle work on UWP; Add CollapsedPaneWidth specific property * Toolbar now working with both collapse styles * MDP now displaying Content title; toolbar routing around title * Add a gallery for the iOS NavigationPage stuff * Add Navigation Page as detail page to verify it works with new Toolbar options * Make titlebar/toolbar background colors consistent * ToolbarPlacement now working on NavigationPage * Toolbar Placement working for tabbed and nav pages * Fix bug where phone doesn't get default toolbar placement on start * [Core] Add PS WindowSoftInputModeAdjust [Core] Make Application extendable * Toolbar placement now working on Nav, Tabbed, and Master pages on desktop/phone Remove unnecessary style indirection Fix build errors * [A] Add PlatformConfigurationExtensions * SetSoftInputMode test page * [A] SetSoftInputMode Known issue: Status bar color does not work in AdjustResize mode * [Core] Add PS Blur * [iOS] Configure renderer for blur * Add test page * Move to blur VisualElement for broader support * Move test pages to gallery * Update docs * Use lazy initializer for PlatformConfigurationRegistry
2016-08-30 20:46:14 +03:00
public class Page : VisualElement, ILayout, IPageController, IElementConfiguration<Page>
2016-03-22 23:02:25 +03:00
{
public const string BusySetSignalName = "Xamarin.BusySet";
2016-03-22 23:02:25 +03:00
public const string AlertSignalName = "Xamarin.SendAlert";
2016-03-22 23:02:25 +03:00
public const string ActionSheetSignalName = "Xamarin.ShowActionSheet";
2016-03-22 23:02:25 +03:00
internal static readonly BindableProperty IgnoresContainerAreaProperty = BindableProperty.Create("IgnoresContainerArea", typeof(bool), typeof(Page), false);
public static readonly BindableProperty BackgroundImageProperty = BindableProperty.Create("BackgroundImage", typeof(string), typeof(Page), default(string));
public static readonly BindableProperty IsBusyProperty = BindableProperty.Create("IsBusy", typeof(bool), typeof(Page), false, propertyChanged: (bo, o, n) => ((Page)bo).OnPageBusyChanged());
public static readonly BindableProperty PaddingProperty = BindableProperty.Create("Padding", typeof(Thickness), typeof(Page), default(Thickness), propertyChanged: (bindable, old, newValue) =>
{
var layout = (Page)bindable;
layout.UpdateChildrenLayout();
});
public static readonly BindableProperty TitleProperty = BindableProperty.Create("Title", typeof(string), typeof(Page), null);
public static readonly BindableProperty IconProperty = BindableProperty.Create("Icon", typeof(FileImageSource), typeof(Page), default(FileImageSource));
Platform Specifics (#301) * Playing around with how the platform specifics interfaces etc. might work * Sample implementation of iOS navigation translucency * Very slightly reduced code * Better vendor stuff * Drop single-implemenation interfaces * Generics on NavigationPage * On-demand vendor stuff * Remove functionally duplicate classes and make ControlGallery work again * Namespace all the things. XAML test. * Can use Effect to attach platform specific * Attach Effect on PropertyChanging for XAML support! * Rename IConfigPlatform interfaces for readability * Some renaming to match the documents * Split class files * Clear out test-only code * Re-namespace * Added On method to rendered Elements * Allow for removal of platform suffix, convenience methods on specific platforms * Creating a gallery page for specifics * Add rudimentary Platform Specifics gallery; make CollapseStyle work on UWP; Add CollapsedPaneWidth specific property * Toolbar now working with both collapse styles * MDP now displaying Content title; toolbar routing around title * Add a gallery for the iOS NavigationPage stuff * Add Navigation Page as detail page to verify it works with new Toolbar options * Make titlebar/toolbar background colors consistent * ToolbarPlacement now working on NavigationPage * Toolbar Placement working for tabbed and nav pages * Fix bug where phone doesn't get default toolbar placement on start * [Core] Add PS WindowSoftInputModeAdjust [Core] Make Application extendable * Toolbar placement now working on Nav, Tabbed, and Master pages on desktop/phone Remove unnecessary style indirection Fix build errors * [A] Add PlatformConfigurationExtensions * SetSoftInputMode test page * [A] SetSoftInputMode Known issue: Status bar color does not work in AdjustResize mode * [Core] Add PS Blur * [iOS] Configure renderer for blur * Add test page * Move to blur VisualElement for broader support * Move test pages to gallery * Update docs * Use lazy initializer for PlatformConfigurationRegistry
2016-08-30 20:46:14 +03:00
readonly Lazy<PlatformConfigurationRegistry<Page>> _platformConfigurationRegistry;
2016-03-22 23:02:25 +03:00
bool _allocatedFlag;
Rectangle _containerArea;
bool _containerAreaSet;
bool _hasAppeared;
ReadOnlyCollection<Element> _logicalChildren;
IPageController PageController => this as IPageController;
IElementController ElementController => this as IElementController;
2016-03-22 23:02:25 +03:00
public Page()
{
var toolbarItems = new ObservableCollection<ToolbarItem>();
toolbarItems.CollectionChanged += OnToolbarItemsCollectionChanged;
ToolbarItems = toolbarItems;
PageController.InternalChildren.CollectionChanged += InternalChildrenOnCollectionChanged;
Platform Specifics (#301) * Playing around with how the platform specifics interfaces etc. might work * Sample implementation of iOS navigation translucency * Very slightly reduced code * Better vendor stuff * Drop single-implemenation interfaces * Generics on NavigationPage * On-demand vendor stuff * Remove functionally duplicate classes and make ControlGallery work again * Namespace all the things. XAML test. * Can use Effect to attach platform specific * Attach Effect on PropertyChanging for XAML support! * Rename IConfigPlatform interfaces for readability * Some renaming to match the documents * Split class files * Clear out test-only code * Re-namespace * Added On method to rendered Elements * Allow for removal of platform suffix, convenience methods on specific platforms * Creating a gallery page for specifics * Add rudimentary Platform Specifics gallery; make CollapseStyle work on UWP; Add CollapsedPaneWidth specific property * Toolbar now working with both collapse styles * MDP now displaying Content title; toolbar routing around title * Add a gallery for the iOS NavigationPage stuff * Add Navigation Page as detail page to verify it works with new Toolbar options * Make titlebar/toolbar background colors consistent * ToolbarPlacement now working on NavigationPage * Toolbar Placement working for tabbed and nav pages * Fix bug where phone doesn't get default toolbar placement on start * [Core] Add PS WindowSoftInputModeAdjust [Core] Make Application extendable * Toolbar placement now working on Nav, Tabbed, and Master pages on desktop/phone Remove unnecessary style indirection Fix build errors * [A] Add PlatformConfigurationExtensions * SetSoftInputMode test page * [A] SetSoftInputMode Known issue: Status bar color does not work in AdjustResize mode * [Core] Add PS Blur * [iOS] Configure renderer for blur * Add test page * Move to blur VisualElement for broader support * Move test pages to gallery * Update docs * Use lazy initializer for PlatformConfigurationRegistry
2016-08-30 20:46:14 +03:00
_platformConfigurationRegistry = new Lazy<PlatformConfigurationRegistry<Page>>(() => new PlatformConfigurationRegistry<Page>(this));
2016-03-22 23:02:25 +03:00
}
public string BackgroundImage
{
get { return (string)GetValue(BackgroundImageProperty); }
set { SetValue(BackgroundImageProperty, value); }
}
public FileImageSource Icon
{
get { return (FileImageSource)GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public bool IsBusy
{
get { return (bool)GetValue(IsBusyProperty); }
set { SetValue(IsBusyProperty, value); }
}
public Thickness Padding
{
get { return (Thickness)GetValue(PaddingProperty); }
set { SetValue(PaddingProperty, value); }
}
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public IList<ToolbarItem> ToolbarItems { get; internal set; }
Rectangle IPageController.ContainerArea
2016-03-22 23:02:25 +03:00
{
get { return _containerArea; }
set
{
if (_containerArea == value)
return;
_containerAreaSet = true;
_containerArea = value;
ForceLayout();
}
}
bool IPageController.IgnoresContainerArea
2016-03-22 23:02:25 +03:00
{
get { return (bool)GetValue(IgnoresContainerAreaProperty); }
set { SetValue(IgnoresContainerAreaProperty, value); }
}
ObservableCollection<Element> IPageController.InternalChildren { get; } = new ObservableCollection<Element>();
2016-03-22 23:02:25 +03:00
internal override ReadOnlyCollection<Element> LogicalChildrenInternal =>
_logicalChildren ?? (_logicalChildren = new ReadOnlyCollection<Element>(PageController.InternalChildren));
2016-03-22 23:02:25 +03:00
public event EventHandler LayoutChanged;
public event EventHandler Appearing;
public event EventHandler Disappearing;
public Task<string> DisplayActionSheet(string title, string cancel, string destruction, params string[] buttons)
{
var args = new ActionSheetArguments(title, cancel, destruction, buttons);
MessagingCenter.Send(this, ActionSheetSignalName, args);
return args.Result.Task;
}
public Task DisplayAlert(string title, string message, string cancel)
{
return DisplayAlert(title, message, null, cancel);
}
public Task<bool> DisplayAlert(string title, string message, string accept, string cancel)
{
if (string.IsNullOrEmpty(cancel))
throw new ArgumentNullException("cancel");
var args = new AlertArguments(title, message, accept, cancel);
MessagingCenter.Send(this, AlertSignalName, args);
return args.Result.Task;
}
public void ForceLayout()
{
SizeAllocated(Width, Height);
}
public bool SendBackButtonPressed()
{
return OnBackButtonPressed();
}
protected virtual void LayoutChildren(double x, double y, double width, double height)
{
var area = new Rectangle(x, y, width, height);
Rectangle originalArea = area;
if (_containerAreaSet)
{
area = PageController.ContainerArea;
2016-03-22 23:02:25 +03:00
area.X += Padding.Left;
area.Y += Padding.Right;
area.Width -= Padding.HorizontalThickness;
area.Height -= Padding.VerticalThickness;
area.Width = Math.Max(0, area.Width);
area.Height = Math.Max(0, area.Height);
}
List<Element> elements = ElementController.LogicalChildren.ToList();
foreach (Element element in elements)
2016-03-22 23:02:25 +03:00
{
var child = element as VisualElement;
if (child == null)
continue;
var page = child as Page;
if (page != null && ((IPageController)page).IgnoresContainerArea)
2016-03-22 23:02:25 +03:00
Forms.Layout.LayoutChildIntoBoundingRegion(child, originalArea);
else
Forms.Layout.LayoutChildIntoBoundingRegion(child, area);
}
}
protected virtual void OnAppearing()
{
}
protected virtual bool OnBackButtonPressed()
{
var application = RealParent as Application;
if (application == null || this == application.MainPage)
return false;
var canceled = false;
EventHandler handler = (sender, args) => { canceled = true; };
application.PopCanceled += handler;
Navigation.PopModalAsync().ContinueWith(t => { throw t.Exception; }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());
application.PopCanceled -= handler;
return !canceled;
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
foreach (ToolbarItem toolbarItem in ToolbarItems)
{
SetInheritedBindingContext(toolbarItem, BindingContext);
}
}
protected virtual void OnChildMeasureInvalidated(object sender, EventArgs e)
{
InvalidationTrigger trigger = (e as InvalidationEventArgs)?.Trigger ?? InvalidationTrigger.Undefined;
OnChildMeasureInvalidated((VisualElement)sender, trigger);
}
protected virtual void OnDisappearing()
{
}
protected override void OnParentSet()
{
if (!Application.IsApplicationOrNull(RealParent) && !(RealParent is Page))
throw new InvalidOperationException("Parent of a Page must also be a Page");
base.OnParentSet();
}
protected override void OnSizeAllocated(double width, double height)
{
_allocatedFlag = true;
base.OnSizeAllocated(width, height);
UpdateChildrenLayout();
}
protected void UpdateChildrenLayout()
{
if (!ShouldLayoutChildren())
return;
var startingLayout = new List<Rectangle>(ElementController.LogicalChildren.Count);
foreach (VisualElement c in ElementController.LogicalChildren)
2016-03-22 23:02:25 +03:00
{
startingLayout.Add(c.Bounds);
}
double x = Padding.Left;
double y = Padding.Top;
double w = Math.Max(0, Width - Padding.HorizontalThickness);
double h = Math.Max(0, Height - Padding.VerticalThickness);
LayoutChildren(x, y, w, h);
for (var i = 0; i < ElementController.LogicalChildren.Count; i++)
2016-03-22 23:02:25 +03:00
{
var c = (VisualElement)ElementController.LogicalChildren[i];
2016-03-22 23:02:25 +03:00
if (c.Bounds != startingLayout[i])
{
EventHandler handler = LayoutChanged;
if (handler != null)
handler(this, EventArgs.Empty);
return;
}
}
}
internal virtual void OnChildMeasureInvalidated(VisualElement child, InvalidationTrigger trigger)
{
var container = this as IPageContainer<Page>;
if (container != null)
{
Page page = container.CurrentPage;
if (page != null && page.IsVisible && (!page.IsPlatformEnabled || !page.IsNativeStateConsistent))
return;
}
else
{
for (var i = 0; i < ElementController.LogicalChildren.Count; i++)
2016-03-22 23:02:25 +03:00
{
var v = ElementController.LogicalChildren[i] as VisualElement;
2016-03-22 23:02:25 +03:00
if (v != null && v.IsVisible && (!v.IsPlatformEnabled || !v.IsNativeStateConsistent))
return;
}
}
_allocatedFlag = false;
InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
2016-03-22 23:02:25 +03:00
if (!_allocatedFlag && Width >= 0 && Height >= 0)
{
SizeAllocated(Width, Height);
}
}
void IPageController.SendAppearing()
2016-03-22 23:02:25 +03:00
{
if (_hasAppeared)
return;
_hasAppeared = true;
if (IsBusy)
MessagingCenter.Send(this, BusySetSignalName, true);
OnAppearing();
EventHandler handler = Appearing;
if (handler != null)
handler(this, EventArgs.Empty);
var pageContainer = this as IPageContainer<Page>;
((IPageController)pageContainer?.CurrentPage)?.SendAppearing();
2016-03-22 23:02:25 +03:00
}
void IPageController.SendDisappearing()
2016-03-22 23:02:25 +03:00
{
if (!_hasAppeared)
return;
_hasAppeared = false;
if (IsBusy)
MessagingCenter.Send(this, BusySetSignalName, false);
var pageContainer = this as IPageContainer<Page>;
((IPageController)pageContainer?.CurrentPage)?.SendDisappearing();
2016-03-22 23:02:25 +03:00
OnDisappearing();
EventHandler handler = Disappearing;
if (handler != null)
handler(this, EventArgs.Empty);
}
void InternalChildrenOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.OldItems != null)
{
foreach (VisualElement item in e.OldItems.OfType<VisualElement>())
OnInternalRemoved(item);
}
if (e.NewItems != null)
{
foreach (VisualElement item in e.NewItems.OfType<VisualElement>())
OnInternalAdded(item);
}
}
void OnInternalAdded(VisualElement view)
{
view.MeasureInvalidated += OnChildMeasureInvalidated;
OnChildAdded(view);
InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
2016-03-22 23:02:25 +03:00
}
void OnInternalRemoved(VisualElement view)
{
view.MeasureInvalidated -= OnChildMeasureInvalidated;
OnChildRemoved(view);
}
void OnPageBusyChanged()
{
if (!_hasAppeared)
return;
MessagingCenter.Send(this, BusySetSignalName, IsBusy);
}
void OnToolbarItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
{
if (args.Action != NotifyCollectionChangedAction.Add)
return;
foreach (IElement item in args.NewItems)
item.Parent = this;
}
bool ShouldLayoutChildren()
{
if (!ElementController.LogicalChildren.Any() || Width <= 0 || Height <= 0 || !IsNativeStateConsistent)
2016-03-22 23:02:25 +03:00
return false;
var container = this as IPageContainer<Page>;
if (container?.CurrentPage != null)
2016-03-22 23:02:25 +03:00
{
if (PageController.InternalChildren.Contains(container.CurrentPage))
2016-03-22 23:02:25 +03:00
return container.CurrentPage.IsPlatformEnabled && container.CurrentPage.IsNativeStateConsistent;
return true;
}
var any = false;
for (var i = 0; i < ElementController.LogicalChildren.Count; i++)
2016-03-22 23:02:25 +03:00
{
var v = ElementController.LogicalChildren[i] as VisualElement;
2016-03-22 23:02:25 +03:00
if (v != null && (!v.IsPlatformEnabled || !v.IsNativeStateConsistent))
{
any = true;
break;
}
}
return !any;
}
Platform Specifics (#301) * Playing around with how the platform specifics interfaces etc. might work * Sample implementation of iOS navigation translucency * Very slightly reduced code * Better vendor stuff * Drop single-implemenation interfaces * Generics on NavigationPage * On-demand vendor stuff * Remove functionally duplicate classes and make ControlGallery work again * Namespace all the things. XAML test. * Can use Effect to attach platform specific * Attach Effect on PropertyChanging for XAML support! * Rename IConfigPlatform interfaces for readability * Some renaming to match the documents * Split class files * Clear out test-only code * Re-namespace * Added On method to rendered Elements * Allow for removal of platform suffix, convenience methods on specific platforms * Creating a gallery page for specifics * Add rudimentary Platform Specifics gallery; make CollapseStyle work on UWP; Add CollapsedPaneWidth specific property * Toolbar now working with both collapse styles * MDP now displaying Content title; toolbar routing around title * Add a gallery for the iOS NavigationPage stuff * Add Navigation Page as detail page to verify it works with new Toolbar options * Make titlebar/toolbar background colors consistent * ToolbarPlacement now working on NavigationPage * Toolbar Placement working for tabbed and nav pages * Fix bug where phone doesn't get default toolbar placement on start * [Core] Add PS WindowSoftInputModeAdjust [Core] Make Application extendable * Toolbar placement now working on Nav, Tabbed, and Master pages on desktop/phone Remove unnecessary style indirection Fix build errors * [A] Add PlatformConfigurationExtensions * SetSoftInputMode test page * [A] SetSoftInputMode Known issue: Status bar color does not work in AdjustResize mode * [Core] Add PS Blur * [iOS] Configure renderer for blur * Add test page * Move to blur VisualElement for broader support * Move test pages to gallery * Update docs * Use lazy initializer for PlatformConfigurationRegistry
2016-08-30 20:46:14 +03:00
public IPlatformElementConfiguration<T, Page> On<T>() where T : IConfigPlatform
{
return _platformConfigurationRegistry.Value.On<T>();
}
2016-03-22 23:02:25 +03:00
}
}