Add ability to add component frame using runtime type object instead of generic param
This commit is contained in:
parent
535b601d55
commit
acc5b9461b
|
|
@ -148,16 +148,27 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
/// <typeparam name="TComponent">The type of the child component.</typeparam>
|
||||
/// <param name="sequence">An integer that represents the position of the instruction in the source code.</param>
|
||||
public void OpenComponent<TComponent>(int sequence) where TComponent : IComponent
|
||||
=> OpenComponentUnchecked(sequence, typeof(TComponent));
|
||||
|
||||
/// <summary>
|
||||
/// Appends a frame representing a child component.
|
||||
/// </summary>
|
||||
/// <param name="sequence">An integer that represents the position of the instruction in the source code.</param>
|
||||
/// <param name="componentType">The type of the child component.</param>
|
||||
public void OpenComponent(int sequence, Type componentType)
|
||||
{
|
||||
if (!typeof(IComponent).IsAssignableFrom(componentType))
|
||||
{
|
||||
throw new ArgumentException($"The component type must implement {typeof(IComponent).FullName}.");
|
||||
}
|
||||
|
||||
OpenComponentUnchecked(sequence, componentType);
|
||||
}
|
||||
|
||||
private void OpenComponentUnchecked(int sequence, Type componentType)
|
||||
{
|
||||
// Currently, child components can't have further grandchildren of their own, so it would
|
||||
// technically be possible to skip their CloseElement calls and not track them in _openElementIndices.
|
||||
// However at some point we might want to have the grandchildren frames available at runtime
|
||||
// (rather than being parsed as attributes at compile time) so that we could have APIs for
|
||||
// components to query the complete hierarchy of transcluded frames instead of forcing the
|
||||
// transcluded subtree to be in a particular shape such as representing key/value pairs.
|
||||
// So it's more flexible if we track open/close frames for components explicitly.
|
||||
_openElementIndices.Push(_entries.Count);
|
||||
Append(RenderTreeFrame.ChildComponent<TComponent>(sequence));
|
||||
Append(RenderTreeFrame.ChildComponent(sequence, componentType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -201,8 +201,8 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
|
|||
internal static RenderTreeFrame Attribute(int sequence, string name, object value)
|
||||
=> new RenderTreeFrame(sequence, attributeName: name, attributeValue: value);
|
||||
|
||||
internal static RenderTreeFrame ChildComponent<T>(int sequence) where T : IComponent
|
||||
=> new RenderTreeFrame(sequence, typeof(T), 0);
|
||||
internal static RenderTreeFrame ChildComponent(int sequence, Type componentType)
|
||||
=> new RenderTreeFrame(sequence, componentType, 0);
|
||||
|
||||
internal static RenderTreeFrame Region(int sequence)
|
||||
=> new RenderTreeFrame(sequence, regionSubtreeLength: 0);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
// Arrange
|
||||
var frames = new[]
|
||||
{
|
||||
RenderTreeFrame.ChildComponent<FakeComponent>(0).WithComponentSubtreeLength(1)
|
||||
RenderTreeFrame.ChildComponent(0, typeof(FakeComponent)).WithComponentSubtreeLength(1)
|
||||
};
|
||||
var parameterCollection = new ParameterCollection(frames, 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void CanAddChildComponents()
|
||||
public void CanAddChildComponentsUsingGenericParam()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new RenderTreeBuilder(new TestRenderer());
|
||||
|
|
@ -286,6 +286,34 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
|||
frame => AssertFrame.Attribute(frame, "child2attribute", "C"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanAddChildComponentsUsingTypeArgument()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new RenderTreeBuilder(new TestRenderer());
|
||||
|
||||
// Act
|
||||
var componentType = typeof(TestComponent);
|
||||
builder.OpenElement(10, "parent"); // 0: <parent>
|
||||
builder.OpenComponent(11, componentType); // 1: <testcomponent
|
||||
builder.AddAttribute(12, "child1attribute1", "A"); // 2: child1attribute1="A"
|
||||
builder.AddAttribute(13, "child1attribute2", "B"); // 3: child1attribute2="B">
|
||||
builder.CloseComponent(); // </testcomponent>
|
||||
builder.OpenComponent(14, componentType); // 4: <testcomponent
|
||||
builder.AddAttribute(15, "child2attribute", "C"); // 5: child2attribute="C">
|
||||
builder.CloseComponent(); // </testcomponent>
|
||||
builder.CloseElement(); // </parent>
|
||||
|
||||
// Assert
|
||||
Assert.Collection(builder.GetFrames(),
|
||||
frame => AssertFrame.Element(frame, "parent", 6),
|
||||
frame => AssertFrame.Component<TestComponent>(frame),
|
||||
frame => AssertFrame.Attribute(frame, "child1attribute1", "A"),
|
||||
frame => AssertFrame.Attribute(frame, "child1attribute2", "B"),
|
||||
frame => AssertFrame.Component<TestComponent>(frame),
|
||||
frame => AssertFrame.Attribute(frame, "child2attribute", "C"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanAddRegions()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue