Define RenderFragment concept

This commit is contained in:
Steve Sanderson 2018-02-16 09:04:47 +00:00
parent 1ac5ee25c1
commit 29a6175ac1
9 changed files with 35 additions and 25 deletions

View File

@ -20,14 +20,14 @@ namespace Microsoft.AspNetCore.Blazor.Components
{ {
public const string BuildRenderTreeMethodName = nameof(BuildRenderTree); public const string BuildRenderTreeMethodName = nameof(BuildRenderTree);
private readonly Action<RenderTreeBuilder> _renderAction; private readonly RenderFragment _renderFragment;
private RenderHandle _renderHandle; private RenderHandle _renderHandle;
private bool _hasNeverRendered = true; private bool _hasNeverRendered = true;
private bool _hasPendingQueuedRender; private bool _hasPendingQueuedRender;
public BlazorComponent() public BlazorComponent()
{ {
_renderAction = BuildRenderTree; _renderFragment = BuildRenderTree;
} }
/// <summary> /// <summary>
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Blazor.Components
if (_hasNeverRendered || ShouldRender()) if (_hasNeverRendered || ShouldRender())
{ {
_hasPendingQueuedRender = true; _hasPendingQueuedRender = true;
_renderHandle.Render(_renderAction); _renderHandle.Render(_renderFragment);
} }
} }

View File

@ -31,14 +31,15 @@ namespace Microsoft.AspNetCore.Blazor.Components
/// <summary> /// <summary>
/// Notifies the renderer that the component should be rendered. /// Notifies the renderer that the component should be rendered.
/// </summary> /// </summary>
public void Render(Action<RenderTreeBuilder> renderAction) /// <param name="renderFragment">The content that should be rendered.</param>
public void Render(RenderFragment renderFragment)
{ {
if (_renderer == null) if (_renderer == null)
{ {
throw new InvalidOperationException("The render handle is not yet assigned."); throw new InvalidOperationException("The render handle is not yet assigned.");
} }
_renderer.AddToRenderQueue(new RenderQueueEntry(_componentId, renderAction)); _renderer.AddToRenderQueue(new RenderQueueEntry(_componentId, renderFragment));
} }
} }
} }

View File

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.Blazor.RenderTree
{
/// <summary>
/// Represents a segment of UI content, implemented as a delegate that
/// writes the content to a <see cref="RenderTreeBuilder"/>.
/// </summary>
/// <param name="builder">The <see cref="RenderTreeBuilder"/> to which the content should be written.</param>
public delegate void RenderFragment(RenderTreeBuilder builder);
}

View File

@ -35,13 +35,13 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
_renderTreeBuilderPrevious = new RenderTreeBuilder(renderer); _renderTreeBuilderPrevious = new RenderTreeBuilder(renderer);
} }
public void RenderIntoBatch(RenderBatchBuilder batchBuilder, Action<RenderTreeBuilder> renderAction) public void RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment)
{ {
// Swap the old and new tree builders // Swap the old and new tree builders
(_renderTreeBuilderCurrent, _renderTreeBuilderPrevious) = (_renderTreeBuilderPrevious, _renderTreeBuilderCurrent); (_renderTreeBuilderCurrent, _renderTreeBuilderPrevious) = (_renderTreeBuilderPrevious, _renderTreeBuilderCurrent);
_renderTreeBuilderCurrent.Clear(); _renderTreeBuilderCurrent.Clear();
renderAction(_renderTreeBuilderCurrent); renderFragment(_renderTreeBuilderCurrent);
var diff = RenderTreeDiffBuilder.ComputeDiff( var diff = RenderTreeDiffBuilder.ComputeDiff(
_renderer, _renderer,

View File

@ -9,12 +9,12 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
internal readonly struct RenderQueueEntry internal readonly struct RenderQueueEntry
{ {
public readonly int ComponentId; public readonly int ComponentId;
public readonly Action<RenderTreeBuilder> RenderAction; public readonly RenderFragment RenderFragment;
public RenderQueueEntry(int componentId, Action<RenderTreeBuilder> renderAction) public RenderQueueEntry(int componentId, RenderFragment renderFragment)
{ {
ComponentId = componentId; ComponentId = componentId;
RenderAction = renderAction ?? throw new ArgumentNullException(nameof(renderAction)); RenderFragment = renderFragment ?? throw new ArgumentNullException(nameof(renderFragment));
} }
} }
} }

View File

@ -145,7 +145,7 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
{ {
var componentId = renderQueueEntry.ComponentId; var componentId = renderQueueEntry.ComponentId;
GetRequiredComponentState(componentId) GetRequiredComponentState(componentId)
.RenderIntoBatch(_batchBuilder, renderQueueEntry.RenderAction); .RenderIntoBatch(_batchBuilder, renderQueueEntry.RenderFragment);
// Process disposal queue now in case it causes further component renders to be enqueued // Process disposal queue now in case it causes further component renders to be enqueued
while (_batchBuilder.ComponentDisposalQueue.Count > 0) while (_batchBuilder.ComponentDisposalQueue.Count > 0)

View File

@ -27,11 +27,11 @@ namespace Microsoft.AspNetCore.Blazor.Test
[Theory] [Theory]
[MemberData(nameof(RecognizesEquivalentFramesAsSameCases))] [MemberData(nameof(RecognizesEquivalentFramesAsSameCases))]
public void RecognizesEquivalentFramesAsSame(Action<RenderTreeBuilder> appendAction) public void RecognizesEquivalentFramesAsSame(RenderFragment appendFragment)
{ {
// Arrange // Arrange
appendAction(oldTree); appendFragment(oldTree);
appendAction(newTree); appendFragment(newTree);
// Act // Act
var (result, referenceFrames) = GetSingleUpdatedComponent(initializeFromFrames: true); var (result, referenceFrames) = GetSingleUpdatedComponent(initializeFromFrames: true);
@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
} }
public static IEnumerable<object[]> RecognizesEquivalentFramesAsSameCases() public static IEnumerable<object[]> RecognizesEquivalentFramesAsSameCases()
=> new Action<RenderTreeBuilder>[] => new RenderFragment[]
{ {
builder => builder.AddContent(0, "Hello"), builder => builder.AddContent(0, "Hello"),
builder => builder.OpenElement(0, "Some Element"), builder => builder.OpenElement(0, "Some Element"),

View File

@ -790,11 +790,11 @@ namespace Microsoft.AspNetCore.Blazor.Test
private class TestComponent : IComponent private class TestComponent : IComponent
{ {
private RenderHandle _renderHandle; private RenderHandle _renderHandle;
private Action<RenderTreeBuilder> _renderAction; private RenderFragment _renderFragment;
public TestComponent(Action<RenderTreeBuilder> renderAction) public TestComponent(RenderFragment renderFragment)
{ {
_renderAction = renderAction; _renderFragment = renderFragment;
} }
public void Init(RenderHandle renderHandle) public void Init(RenderHandle renderHandle)
@ -806,7 +806,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
=> TriggerRender(); => TriggerRender();
public void TriggerRender() public void TriggerRender()
=> _renderHandle.Render(_renderAction); => _renderHandle.Render(_renderFragment);
} }
private class MessageComponent : AutoRenderComponent private class MessageComponent : AutoRenderComponent

View File

@ -12,16 +12,13 @@ namespace BasicTestApp
private RenderHandle _renderHandle; private RenderHandle _renderHandle;
private bool _showRegion; private bool _showRegion;
// Important: Notice that the sequence numbers inside the region are higher // Important: Notice that the sequence numbers inside the fragment are higher
// that the sequence numbers outside it. Without the region delimiter, the // that the sequence numbers outside it. Without the region delimiter, the
// differencer would think the following nodes had been removed, then the // differencer would think the following nodes had been removed, then the
// region was inserted, followed by a new copy of the following nodes. That's // region was inserted, followed by a new copy of the following nodes. That's
// not as efficient and wouldn't preserve focus etc. // not as efficient and wouldn't preserve focus etc.
private Action<RenderTreeBuilder> _exampleRegion = builder => private RenderFragment _exampleContent = builder =>
{ {
// TODO: Support some kind of RenderBlock primitive
// which is an Action<RenderTreeBuilder>. Can use the
// same type name for RenderHandle.Render's arg.
builder.OpenElement(100, "p"); builder.OpenElement(100, "p");
builder.AddAttribute(101, "name", "region-element"); builder.AddAttribute(101, "name", "region-element");
builder.AddAttribute(102, "style", "color: red"); builder.AddAttribute(102, "style", "color: red");
@ -52,7 +49,7 @@ namespace BasicTestApp
if (_showRegion) if (_showRegion)
{ {
builder.OpenRegion(3); builder.OpenRegion(3);
_exampleRegion(builder); _exampleContent(builder);
builder.CloseRegion(); builder.CloseRegion();
} }