This commit is contained in:
Oleksandr Liakhevych 2021-03-08 16:19:49 +02:00 коммит произвёл Eilon Lipton
Родитель e5b2a6d394
Коммит 83343727fe
11 изменённых файлов: 282 добавлений и 17 удалений

Просмотреть файл

@ -1,30 +1,38 @@
<ContentPage Title="Shell Properties">
<ShellProperties NavBarIsVisible="navBarVisible"
TabBarIsVisible="tabBarVisible"
TitleColor="titleColor" />
<ContentPage @ref="page">
<ToolbarItems>
<ToolbarItem Text="Help" OnClick="ShowHelp" />
</ToolbarItems>
<StackLayout>
<StackLayout Orientation="StackOrientation.Horizontal">
<Label Text="Enable NavBar: " />
<CheckBox @bind-IsChecked="navBarVisible" />
<ChildContent>
<ShellProperties NavBarIsVisible="navBarVisible"
TabBarIsVisible="tabBarVisible"
TitleColor="titleColor" />
<StackLayout>
<StackLayout Orientation="StackOrientation.Horizontal">
<Label Text="Enable NavBar: " />
<CheckBox @bind-IsChecked="navBarVisible" />
</StackLayout>
<StackLayout Orientation="StackOrientation.Horizontal">
<Label Text="Enable TabBar: " />
<CheckBox @bind-IsChecked="tabBarVisible" />
</StackLayout>
<Button Text="Change Title Color" OnClick="ChangeTitleColor" />
</StackLayout>
<StackLayout Orientation="StackOrientation.Horizontal">
<Label Text="Enable TabBar: " />
<CheckBox @bind-IsChecked="tabBarVisible" />
</StackLayout>
<Button Text="Change Title Color" OnClick="ChangeTitleColor" />
</StackLayout>
</ChildContent>
</ContentPage>
@code{
Microsoft.MobileBlazorBindings.Elements.Page page;
bool navBarVisible = true;
bool tabBarVisible = true;
Color? titleColor;
List<Color> colors = new List<Color> {
Color.Red,
Color.Green,
Color.Blue
Color.Red,
Color.Green,
Color.Blue
};
void ChangeTitleColor()
@ -32,4 +40,9 @@
var index = (titleColor.HasValue ? colors.IndexOf(titleColor.Value) + 1 : 0) % colors.Count;
titleColor = colors[index];
}
async Task ShowHelp()
{
await page.NativeControl.DisplayAlert("Help", "Some help message", "OK");
}
}

Просмотреть файл

@ -49,6 +49,7 @@ TabbedPage
TemplatedPage
TemplatedView
TimePicker
ToolbarItem
View
VisualElement

Просмотреть файл

@ -23,6 +23,13 @@ namespace Microsoft.MobileBlazorBindings.Core
ElementHandlers.Add(typeof(TComponent).FullName, new ElementHandlerFactory((renderer, _) => factory(renderer)));
}
public static void RegisterPropertyContentHandler<TComponent>(string propertyName,
Func<NativeComponentRenderer, IElementHandler> factory) where TComponent : NativeControlComponentBase
{
var key = $"p-{typeof(TComponent).FullName}.{propertyName}";
ElementHandlers.Add(key, new ElementHandlerFactory((renderer, _) => factory(renderer)));
}
public static void RegisterElementHandler<TComponent, TControlHandler>() where TComponent : NativeControlComponentBase where TControlHandler : class, IElementHandler, new()
{
RegisterElementHandler<TComponent>((_, __) => new TControlHandler());

Просмотреть файл

@ -32,6 +32,9 @@ namespace Microsoft.MobileBlazorBindings.Core
builder.AddContent(2, childContent);
}
int sequence = 3;
RenderAdditionalElementContent(builder, ref sequence);
builder.CloseElement();
}
@ -39,6 +42,10 @@ namespace Microsoft.MobileBlazorBindings.Core
{
}
protected virtual void RenderAdditionalElementContent(RenderTreeBuilder builder, ref int sequence)
{
}
protected virtual RenderFragment GetChildContent() => null;
}
}

Просмотреть файл

@ -0,0 +1,63 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using Microsoft.MobileBlazorBindings.Core;
using System;
using System.Collections.Generic;
using XF = Xamarin.Forms;
namespace Microsoft.MobileBlazorBindings.Elements.Handlers
{
public class ListContentPropertyHandler<TElementType, TItemType> : IXamarinFormsContainerElementHandler, INonChildContainerElement where TItemType : XF.Element
{
private readonly Func<TElementType, IList<TItemType>> _listPropertyAccessor;
private IList<TItemType> _propertyItems;
public ListContentPropertyHandler(Func<TElementType, IList<TItemType>> listPropertyAccessor)
{
_listPropertyAccessor = listPropertyAccessor;
}
public void SetParent(object parentElement)
{
_propertyItems = _listPropertyAccessor((TElementType)parentElement);
}
void IXamarinFormsContainerElementHandler.AddChild(XF.Element child, int physicalSiblingIndex)
{
if (!(child is TItemType typedChild))
{
throw new NotSupportedException($"Cannot add item of type {child?.GetType().Name} to a {typeof(TItemType)} collection.");
}
_propertyItems.Insert(physicalSiblingIndex, typedChild);
}
int IXamarinFormsContainerElementHandler.GetChildIndex(XF.Element child)
{
return _propertyItems.IndexOf(child as TItemType);
}
void IXamarinFormsContainerElementHandler.RemoveChild(XF.Element child)
{
_propertyItems.Remove(child as TItemType);
}
// Because this is a 'fake' element, all matters related to physical trees
// should be no-ops.
object IElementHandler.TargetElement => null;
void IElementHandler.ApplyAttribute(ulong attributeEventHandlerId, string attributeName, object attributeValue, string attributeEventUpdatesAttributeName) { }
XF.Element IXamarinFormsElementHandler.ElementControl => null;
bool IXamarinFormsElementHandler.IsParented() => false;
bool IXamarinFormsElementHandler.IsParentedTo(XF.Element parent) => false;
void IXamarinFormsElementHandler.SetParent(XF.Element parent)
{
// This should never get called. Instead, INonChildContainerElement.SetParent() implemented
// in this class should get called.
throw new NotSupportedException();
}
}
}

Просмотреть файл

@ -0,0 +1,40 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using Microsoft.MobileBlazorBindings.Core;
using System;
using XF = Xamarin.Forms;
namespace Microsoft.MobileBlazorBindings.Elements.Handlers
{
public partial class ToolbarItemHandler : MenuItemHandler
{
public ToolbarItemHandler(NativeComponentRenderer renderer, XF.ToolbarItem toolbarItemControl) : base(renderer, toolbarItemControl)
{
ToolbarItemControl = toolbarItemControl ?? throw new ArgumentNullException(nameof(toolbarItemControl));
Initialize(renderer);
}
partial void Initialize(NativeComponentRenderer renderer);
public XF.ToolbarItem ToolbarItemControl { get; }
public override void ApplyAttribute(ulong attributeEventHandlerId, string attributeName, object attributeValue, string attributeEventUpdatesAttributeName)
{
switch (attributeName)
{
case nameof(XF.ToolbarItem.Order):
ToolbarItemControl.Order = (XF.ToolbarItemOrder)AttributeHelper.GetInt(attributeValue);
break;
case nameof(XF.ToolbarItem.Priority):
ToolbarItemControl.Priority = AttributeHelper.GetInt(attributeValue);
break;
default:
base.ApplyAttribute(attributeEventHandlerId, attributeName, attributeValue, attributeEventUpdatesAttributeName);
break;
}
}
}
}

Просмотреть файл

@ -2,12 +2,21 @@
// Licensed under the MIT license.
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
using Microsoft.MobileBlazorBindings.Core;
using Microsoft.MobileBlazorBindings.Elements.Handlers;
using XF = Xamarin.Forms;
namespace Microsoft.MobileBlazorBindings.Elements
{
public partial class Page : VisualElement
{
static partial void RegisterAdditionalHandlers()
{
ElementHandlerRegistry.RegisterPropertyContentHandler<Page>(nameof(ToolbarItems),
_ => new ListContentPropertyHandler<XF.Page, XF.ToolbarItem>(page => page.ToolbarItems));
}
/// <summary>
/// Indicates that the <see cref="Xamarin.Forms.Page" /> is about to appear.
/// </summary>
@ -18,12 +27,19 @@ namespace Microsoft.MobileBlazorBindings.Elements
/// </summary>
[Parameter] public EventCallback OnDisappearing { get; set; }
[Parameter] public RenderFragment ToolbarItems { get; set; }
#pragma warning disable CA1721 // Property names should not match get methods
[Parameter] public RenderFragment ChildContent { get; set; }
#pragma warning restore CA1721 // Property names should not match get methods
protected override RenderFragment GetChildContent() => ChildContent;
protected override void RenderAdditionalElementContent(RenderTreeBuilder builder, ref int sequence)
{
RenderTreeBuilderHelper.AddContentProperty(builder, sequence++, typeof(Page), nameof(ToolbarItems), ToolbarItems);
}
partial void RenderAdditionalAttributes(AttributesBuilder builder)
{
builder.AddAttribute("onappearing", OnAppearing);

Просмотреть файл

@ -15,6 +15,8 @@ namespace Microsoft.MobileBlazorBindings.Elements
{
ElementHandlerRegistry.RegisterElementHandler<Page>(
renderer => new PageHandler(renderer, new XF.Page()));
RegisterAdditionalHandlers();
}
[Parameter] public XF.ImageSource BackgroundImageSource { get; set; }
@ -66,5 +68,7 @@ namespace Microsoft.MobileBlazorBindings.Elements
}
partial void RenderAdditionalAttributes(AttributesBuilder builder);
static partial void RegisterAdditionalHandlers();
}
}

Просмотреть файл

@ -0,0 +1,25 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
using Microsoft.MobileBlazorBindings.Core;
namespace Microsoft.MobileBlazorBindings.Elements
{
/// <summary>
/// The only purpose of this type is to wrap content property handler, since currently renderer does not allow
/// handlers without corresponding component.
/// </summary>
#pragma warning disable CA1812 // Avoid uninstantiated internal classes. Class is used generically.
internal class PropertyWrapperComponent : NativeControlComponentBase
#pragma warning restore CA1812 // Avoid uninstantiated internal classes
{
[Parameter] public RenderFragment ChildContent { get; set; }
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
ChildContent(builder);
}
}
}

Просмотреть файл

@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using Microsoft.AspNetCore.Components;
using Microsoft.MobileBlazorBindings.Core;
using Microsoft.MobileBlazorBindings.Elements.Handlers;
using System.Threading.Tasks;
using XF = Xamarin.Forms;
namespace Microsoft.MobileBlazorBindings.Elements
{
public partial class ToolbarItem : MenuItem
{
static ToolbarItem()
{
ElementHandlerRegistry.RegisterElementHandler<ToolbarItem>(
renderer => new ToolbarItemHandler(renderer, new XF.ToolbarItem()));
}
/// <summary>
/// Gets or sets a value that indicates on which of the primary, secondary, or default toolbar surfaces to display this <see cref="T:Xamarin.Forms.ToolbarItem" /> element.
/// </summary>
[Parameter] public XF.ToolbarItemOrder? Order { get; set; }
/// <summary>
/// Gets or sets the priority of this <see cref="T:Xamarin.Forms.ToolbarItem" /> element.
/// </summary>
[Parameter] public int? Priority { get; set; }
public new XF.ToolbarItem NativeControl => ((ToolbarItemHandler)ElementHandler).ToolbarItemControl;
protected override void RenderAttributes(AttributesBuilder builder)
{
base.RenderAttributes(builder);
if (Order != null)
{
builder.AddAttribute(nameof(Order), (int)Order.Value);
}
if (Priority != null)
{
builder.AddAttribute(nameof(Priority), Priority.Value);
}
RenderAdditionalAttributes(builder);
}
partial void RenderAdditionalAttributes(AttributesBuilder builder);
}
}

Просмотреть файл

@ -0,0 +1,40 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
using Microsoft.MobileBlazorBindings.Elements;
using System;
namespace Microsoft.MobileBlazorBindings
{
public static class RenderTreeBuilderHelper
{
public static void AddContentProperty(RenderTreeBuilder builder, int sequence, Type containingType, string propertyName, RenderFragment content)
{
if (builder is null)
{
throw new ArgumentNullException(nameof(builder));
}
if (content != null)
{
builder.OpenRegion(sequence);
// Content properties are handled by separate handlers, there rendered as separate child elements.
// Renderer does not support elements without parent components as for now,
// therefore adding empty parent component to workaround that.
builder.OpenComponent<PropertyWrapperComponent>(0);
builder.AddAttribute(1, "ChildContent", (RenderFragment)(builder =>
{
builder.OpenElement(2, $"p-{containingType.FullName}.{propertyName}");
builder.AddContent(3, content);
builder.CloseElement();
}));
builder.CloseComponent();
builder.CloseRegion();
}
}
}
}