Blaxamarin updates: Have file represent ContentPages, add StackLayout

- Redid root Blaxamarin components to represent a ContentPage, which should make it more generically useful in apps
- Added StackLayout component
- But... found a bug in Emblazon where siblingIndex of elements is always 0 (applies to BlinForms and Blaxamarin, but has a more negative effect in Blaxamarin where sibling order always matters, whereas in BlinForms it rarely matters)
This commit is contained in:
Eilon Lipton 2019-08-22 14:00:22 -07:00
Родитель 66ed7e31c1
Коммит bbc0e4a60f
6 изменённых файлов: 113 добавлений и 54 удалений

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

@ -6,19 +6,22 @@ namespace Blaxamarin.Framework
{
public static class Blaxamarin
{
public static void Run<T>(Application app) where T : IComponent
public static ContentPage Run<T>() where T : IComponent
{
var serviceCollection = new ServiceCollection();
var serviceProvider = serviceCollection.BuildServiceProvider();
var renderer = new BlaxamarinRenderer(serviceProvider, app);
renderer.Dispatcher.InvokeAsync(async () =>
var renderer = new BlaxamarinRenderer(serviceProvider);
var result = renderer.Dispatcher.InvokeAsync(async () =>
{
await renderer.AddComponent<T>();
// TODO: Do we need anything similar to what BlinForms does?
//Application.Run(renderer.RootForm);
return renderer.ContentPage;
});
return result.GetAwaiter().GetResult();
}
}
}

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

@ -7,13 +7,12 @@ namespace Blaxamarin.Framework
{
public class BlaxamarinRenderer : EmblazonRenderer<Element>
{
public BlaxamarinRenderer(Microsoft.Extensions.DependencyInjection.ServiceProvider serviceProvider, Application app)
public BlaxamarinRenderer(Microsoft.Extensions.DependencyInjection.ServiceProvider serviceProvider)
: base(serviceProvider)
{
App = app;
}
public Application App { get; }
public ContentPage ContentPage { get; } = new ContentPage();
protected override void InitializeRootAdapter(EmblazonAdapter<Element> adapter)
{
@ -27,9 +26,9 @@ namespace Blaxamarin.Framework
// Dock = DockStyle.Fill,
//};
adapter.TargetControl = App;
adapter.TargetControl = new ContentView();
//RootForm.Controls.Add(adapter.TargetControl);
ContentPage.Content = adapter.TargetControl as View;
}
protected override void HandleException(Exception exception)

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

@ -35,49 +35,57 @@ namespace Blaxamarin.Framework
{
// TODO: What is the set of types that support child elements? Do they all need to be special-cased here? (Maybe...)
if (parentControl is Layout<View> parentAsLayout)
switch (parentControl)
{
var childAsView = childControl as View;
case Layout<View> parentAsLayout:
{
var childAsView = childControl as View;
if (siblingIndex <= parentAsLayout.Children.Count)
{
// WinForms ControlCollection doesn't support Insert(), so add the new child at the end,
// and then re-order the collection to move the control to the correct index.
parentAsLayout.Children.Insert(siblingIndex, childAsView);
}
else
{
Debug.WriteLine($"WARNING: {nameof(AddChildControl)} called with {nameof(siblingIndex)}={siblingIndex}, but parentAsLayout.Children.Count={parentAsLayout.Children.Count}");
parentAsLayout.Children.Add(childAsView);
}
}
else if (parentControl is Application parentAsApp)
{
if (parentAsApp.MainPage != null)
{
Debug.Fail($"Application already has MainPage set; cannot set {parentAsApp.GetType().FullName}'s MainPage to {childControl.GetType().FullName}");
}
else
{
if (childControl is Page childControlAsPage)
{
parentAsApp.MainPage = childControlAsPage;
}
else
{
// TODO: Do we need a BlelementAdapter representing the dummy ContentPage? Or should the Razor page be a ContentPage somehow?
var dummyView = new ContentPage
if (siblingIndex <= parentAsLayout.Children.Count)
{
Content = childControl as View
};
parentAsApp.MainPage = dummyView;
//Debug.Fail($"Application MainPage must be a Page; cannot set {parentAsApp.GetType().FullName}'s MainPage to {childControl.GetType().FullName}");
parentAsLayout.Children.Insert(siblingIndex, childAsView);
}
else
{
Debug.WriteLine($"WARNING: {nameof(AddChildControl)} called with {nameof(siblingIndex)}={siblingIndex}, but parentAsLayout.Children.Count={parentAsLayout.Children.Count}");
parentAsLayout.Children.Add(childAsView);
}
}
}
}
else
{
Debug.Fail($"Don't know how to handle parent control type {parentControl.GetType().FullName} in order to add child {childControl.GetType().FullName}");
break;
case ContentView parentAsContentView:
{
var childAsView = childControl as View;
parentAsContentView.Content = childAsView;
}
break;
case Application parentAsApp:
{
if (parentAsApp.MainPage != null)
{
Debug.Fail($"Application already has MainPage set; cannot set {parentAsApp.GetType().FullName}'s MainPage to {childControl.GetType().FullName}");
}
else
{
if (childControl is Page childControlAsPage)
{
parentAsApp.MainPage = childControlAsPage;
}
else
{
// TODO: Do we need a BlelementAdapter representing the dummy ContentPage? Or should the Razor page be a ContentPage somehow?
var dummyView = new ContentPage
{
Content = childControl as View
};
parentAsApp.MainPage = dummyView;
//Debug.Fail($"Application MainPage must be a Page; cannot set {parentAsApp.GetType().FullName}'s MainPage to {childControl.GetType().FullName}");
}
}
}
break;
default:
Debug.Fail($"Don't know how to handle parent element type {parentControl.GetType().FullName} in order to add child {childControl.GetType().FullName}");
break;
}
}
}

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

@ -0,0 +1,40 @@
using Emblazon;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.RenderTree;
using Xamarin.Forms;
namespace Blaxamarin.Framework.Elements
{
public class StackLayout : FormsComponentBase
{
static StackLayout()
{
BlelementAdapter.KnownElements.Add(typeof(StackLayout).FullName, new ComponentControlFactoryFunc<Element>((_, __) => new BlazorStackLayout()));
}
[Parameter] public RenderFragment ChildContent { get; set; }
protected override void RenderContents(RenderTreeBuilder builder)
{
builder.AddContent(1000, ChildContent);
}
class BlazorStackLayout : Xamarin.Forms.StackLayout, IBlazorNativeControl
{
public BlazorStackLayout()
{
}
public void ApplyAttribute(ulong attributeEventHandlerId, string attributeName, object attributeValue, string attributeEventUpdatesAttributeName)
{
switch (attributeName)
{
default:
FormsComponentBase.ApplyAttribute(this, attributeEventHandlerId, attributeName, attributeValue, attributeEventUpdatesAttributeName);
break;
}
}
}
}
}

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

@ -1,8 +1,5 @@
using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using Xamarin.Forms;
using BlaxamarinSample.Services;
using BlaxamarinSample.Views;
namespace BlaxamarinSample
{
@ -15,7 +12,7 @@ namespace BlaxamarinSample
DependencyService.Register<MockDataStore>();
Blaxamarin.Framework.Blaxamarin.Run<Blaxample>(this);
MainPage = Blaxamarin.Framework.Blaxamarin.Run<Blaxample>();
}
protected override void OnStart()

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

@ -1,7 +1,12 @@
@using Blaxamarin.Framework.Elements
<Button Text="@("Increment: " + count)" OnClick="@IncrementCount" />
<StackLayout>
<Button Text="@("Increment by 1: " + count)" OnClick="@IncrementCount" />
<Button Text="@("Increment by 8: " + count2)" OnClick="@IncrementCount2" />
<Button Text="333"></Button>
<Button Text="444"></Button>
<Button Text="555"></Button>
</StackLayout>
@code {
int count = 0;
@ -10,4 +15,11 @@
{
count++;
}
int count2 = 0;
void IncrementCount2()
{
count2 += 8;
}
}