Begin on setting properties on child components

This commit is contained in:
Steve Sanderson 2018-01-26 08:47:53 -08:00
parent 0aa164073d
commit 9dcb1c4fc4
3 changed files with 77 additions and 19 deletions

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Blazor.Components;
using Microsoft.AspNetCore.Blazor.Rendering;
namespace Microsoft.AspNetCore.Blazor.RenderTree
@ -339,7 +338,7 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
throw new InvalidOperationException($"Child component already exists during {nameof(InstantiateChildComponents)}");
}
_renderer.InstantiateChildComponent(ref nodes[i]);
_renderer.InstantiateChildComponent(nodes, i);
}
}
}

View File

@ -42,23 +42,6 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
}
}
internal void InstantiateChildComponent(ref RenderTreeNode node)
{
if (node.NodeType != RenderTreeNodeType.Component)
{
throw new ArgumentException($"The node's {nameof(RenderTreeNode.NodeType)} property must equal {RenderTreeNodeType.Component}", nameof(node));
}
if (node.Component != null)
{
throw new ArgumentException($"The node already has a non-null component instance", nameof(node));
}
var newComponent = (IComponent)Activator.CreateInstance(node.ComponentType);
var newComponentId = AssignComponentId(newComponent);
node.SetChildComponentInstance(newComponentId, newComponent);
}
/// <summary>
/// Updates the visible UI to display the supplied <paramref name="renderTree"/>
/// at the location corresponding to the <paramref name="componentId"/>.
@ -84,9 +67,46 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
protected void DispatchEvent(int componentId, int renderTreeIndex, UIEventArgs eventArgs)
=> GetRequiredComponentState(componentId).DispatchEvent(renderTreeIndex, eventArgs);
internal void InstantiateChildComponent(RenderTreeNode[] nodes, int componentNodeIndex)
{
ref var node = ref nodes[componentNodeIndex];
if (node.NodeType != RenderTreeNodeType.Component)
{
throw new ArgumentException($"The node's {nameof(RenderTreeNode.NodeType)} property must equal {RenderTreeNodeType.Component}", nameof(node));
}
if (node.Component != null)
{
throw new ArgumentException($"The node already has a non-null component instance", nameof(node));
}
var newComponent = (IComponent)Activator.CreateInstance(node.ComponentType);
var newComponentId = AssignComponentId(newComponent);
node.SetChildComponentInstance(newComponentId, newComponent);
SetPropertiesOnComponent(nodes, componentNodeIndex);
}
private ComponentState GetRequiredComponentState(int componentId)
=> _componentStateById.TryGetValue(componentId, out var componentState)
? componentState
: throw new ArgumentException($"The renderer does not have a component with ID {componentId}.");
private void SetPropertiesOnComponent(RenderTreeNode[] nodes, int componentNodeIndex)
{
ref var componentNode = ref nodes[componentNodeIndex];
var component = componentNode.Component;
var descendantsEndIndex = componentNode.ElementDescendantsEndIndex;
for (var attributeNodeIndex = componentNodeIndex + 1; attributeNodeIndex <= descendantsEndIndex; attributeNodeIndex++)
{
SetPropertyOnComponent(component, nodes[attributeNodeIndex]);
}
}
private void SetPropertyOnComponent(IComponent component, in RenderTreeNode attributeNode)
{
// TODO: Cache the reflection
var property = component.GetType().GetProperty(attributeNode.AttributeName);
property.SetValue(component, attributeNode.AttributeValue);
}
}
}

View File

@ -674,6 +674,39 @@ namespace Microsoft.AspNetCore.Blazor.Test
entry => AssertEdit(entry, RenderTreeEditType.StepOut, 0));
}
[Fact]
public void SetsKnownPropertiesOnChildComponents()
{
// Arrange
var renderer = new FakeRenderer();
var oldTree = new RenderTreeBuilder(renderer);
var newTree = new RenderTreeBuilder(renderer);
var diff = new RenderTreeDiffComputer(renderer);
var testObject = new object();
newTree.OpenComponentElement<FakeComponent>(0);
//newTree.AddAttribute(1, nameof(FakeComponent.IntProperty), 123);
newTree.AddAttribute(2, nameof(FakeComponent.StringProperty), "some string");
//newTree.AddAttribute(3, nameof(FakeComponent.ObjectProperty), testObject);
newTree.CloseElement();
// Act
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
var componentInstance = newTree.GetNodes().First().Component as FakeComponent;
// Assert
AssertEdit(result.Edits.Single(), RenderTreeEditType.PrependNode, 0);
Assert.NotNull(componentInstance);
//Assert.Equal(123, componentInstance.IntProperty);
Assert.Equal("some string", componentInstance.StringProperty);
//Assert.Same(testObject, componentInstance.ObjectProperty);
}
[Fact]
public void RejectsUnknownPropertiesOnChildComponents()
{
}
[Fact]
public void RetainsChildComponentsForExistingNodes()
{
@ -722,6 +755,12 @@ namespace Microsoft.AspNetCore.Blazor.Test
private class FakeComponent : IComponent
{
public int IntProperty { get; set; }
public string StringProperty { get; set; }
public object ObjectProperty { get; set; }
public string ReadonlyProperty { get; private set; }
private string PrivateProperty { get; set; }
public void BuildRenderTree(RenderTreeBuilder builder)
=> throw new NotImplementedException();
}