|
4 | 4 | using System;
|
5 | 5 | using System.Collections.Generic;
|
6 | 6 | using System.Linq;
|
7 |
| -using System.Threading.Tasks; |
8 | 7 | using Microsoft.AspNetCore.Blazor.Components;
|
9 | 8 | using Microsoft.AspNetCore.Blazor.Rendering;
|
10 | 9 | using Microsoft.AspNetCore.Blazor.RenderTree;
|
@@ -1071,6 +1070,94 @@ public void DoesNotCallOnAfterRenderForComponentsNotRendered()
|
1071 | 1070 | Assert.Equal(1, childComponents[2].OnAfterRenderCallCount); // Disposed
|
1072 | 1071 | }
|
1073 | 1072 |
|
| 1073 | + [Fact] |
| 1074 | + public void PassesTreeParametersToNestedComponents() |
| 1075 | + { |
| 1076 | + // Arrange |
| 1077 | + var renderer = new TestRenderer(); |
| 1078 | + var component = new TestComponent(builder => |
| 1079 | + { |
| 1080 | + builder.OpenComponent<Provider<string>>(0); |
| 1081 | + builder.AddAttribute(1, "Value", "Hello"); |
| 1082 | + builder.AddAttribute(2, RenderTreeBuilder.ChildContent, new RenderFragment(childBuilder => |
| 1083 | + { |
| 1084 | + childBuilder.OpenComponent<TreeParameterConsumerComponent<string>>(0); |
| 1085 | + childBuilder.AddAttribute(1, "RegularParameter", "Goodbye"); |
| 1086 | + childBuilder.CloseComponent(); |
| 1087 | + })); |
| 1088 | + builder.CloseComponent(); |
| 1089 | + }); |
| 1090 | + |
| 1091 | + // Act/Assert |
| 1092 | + var componentId = renderer.AssignRootComponentId(component); |
| 1093 | + component.TriggerRender(); |
| 1094 | + var batch = renderer.Batches.Single(); |
| 1095 | + var componentFrame = batch.ReferenceFrames.Single( |
| 1096 | + frame => frame.FrameType == RenderTreeFrameType.Component |
| 1097 | + && frame.Component is TreeParameterConsumerComponent<string>); |
| 1098 | + var nestedComponentId = componentFrame.ComponentId; |
| 1099 | + var nestedComponentDiff = batch.DiffsByComponentId[nestedComponentId].Single(); |
| 1100 | + |
| 1101 | + // The nested component was rendered with the correct parameters |
| 1102 | + Assert.Collection(nestedComponentDiff.Edits, |
| 1103 | + edit => |
| 1104 | + { |
| 1105 | + Assert.Equal(RenderTreeEditType.PrependFrame, edit.Type); |
| 1106 | + AssertFrame.Text( |
| 1107 | + batch.ReferenceFrames[edit.ReferenceFrameIndex], |
| 1108 | + "TreeParameter=Hello; RegularParameter=Goodbye"); |
| 1109 | + }); |
| 1110 | + } |
| 1111 | + |
| 1112 | + [Fact] |
| 1113 | + public void RetainsTreeParametersWhenUpdatingDirectParameters() |
| 1114 | + { |
| 1115 | + // Arrange |
| 1116 | + var renderer = new TestRenderer(); |
| 1117 | + var regularParameterValue = "Initial value"; |
| 1118 | + var component = new TestComponent(builder => |
| 1119 | + { |
| 1120 | + builder.OpenComponent<Provider<string>>(0); |
| 1121 | + builder.AddAttribute(1, "Value", "Hello"); |
| 1122 | + builder.AddAttribute(2, RenderTreeBuilder.ChildContent, new RenderFragment(childBuilder => |
| 1123 | + { |
| 1124 | + childBuilder.OpenComponent<TreeParameterConsumerComponent<string>>(0); |
| 1125 | + childBuilder.AddAttribute(1, "RegularParameter", regularParameterValue); |
| 1126 | + childBuilder.CloseComponent(); |
| 1127 | + })); |
| 1128 | + builder.CloseComponent(); |
| 1129 | + }); |
| 1130 | + |
| 1131 | + // Act 1: Render in initial state |
| 1132 | + var componentId = renderer.AssignRootComponentId(component); |
| 1133 | + component.TriggerRender(); |
| 1134 | + |
| 1135 | + // Capture the nested component so we can verify the update later |
| 1136 | + var firstBatch = renderer.Batches.Single(); |
| 1137 | + var componentFrame = firstBatch.ReferenceFrames.Single( |
| 1138 | + frame => frame.FrameType == RenderTreeFrameType.Component |
| 1139 | + && frame.Component is TreeParameterConsumerComponent<string>); |
| 1140 | + var nestedComponentId = componentFrame.ComponentId; |
| 1141 | + |
| 1142 | + // Act 2: Render again with updated regular parameter |
| 1143 | + regularParameterValue = "Changed value"; |
| 1144 | + component.TriggerRender(); |
| 1145 | + |
| 1146 | + // Assert |
| 1147 | + Assert.Equal(2, renderer.Batches.Count); |
| 1148 | + var secondBatch = renderer.Batches[1]; |
| 1149 | + var nestedComponentDiff = secondBatch.DiffsByComponentId[nestedComponentId].Single(); |
| 1150 | + |
| 1151 | + // The nested component was rendered with the correct parameters |
| 1152 | + Assert.Collection(nestedComponentDiff.Edits, |
| 1153 | + edit => |
| 1154 | + { |
| 1155 | + Assert.Equal(RenderTreeEditType.UpdateText, edit.Type); |
| 1156 | + Assert.Equal(0, edit.ReferenceFrameIndex); // This is the only change |
| 1157 | + AssertFrame.Text(secondBatch.ReferenceFrames[0], "TreeParameter=Hello; RegularParameter=Changed value"); |
| 1158 | + }); |
| 1159 | + } |
| 1160 | + |
1074 | 1161 | private class NoOpRenderer : Renderer
|
1075 | 1162 | {
|
1076 | 1163 | public NoOpRenderer() : base(new TestServiceProvider())
|
@@ -1331,23 +1418,14 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)
|
1331 | 1418 | }
|
1332 | 1419 | }
|
1333 | 1420 |
|
1334 |
| - private class AncestryComponent : AutoRenderComponent |
| 1421 | + class TreeParameterConsumerComponent<T> : AutoRenderComponent |
1335 | 1422 | {
|
1336 |
| - [Parameter] public int NumDescendants { get; private set; } |
| 1423 | + [Parameter(FromTree = true)] T TreeParameter { get; set; } |
| 1424 | + [Parameter] string RegularParameter { get; set; } |
1337 | 1425 |
|
1338 | 1426 | protected override void BuildRenderTree(RenderTreeBuilder builder)
|
1339 | 1427 | {
|
1340 |
| - // Recursively renders more of the same until NumDescendants == 0 |
1341 |
| - if (NumDescendants > 0) |
1342 |
| - { |
1343 |
| - builder.OpenComponent<AncestryComponent>(0); |
1344 |
| - builder.AddAttribute(1, nameof(NumDescendants), NumDescendants - 1); |
1345 |
| - builder.CloseComponent(); |
1346 |
| - } |
1347 |
| - else |
1348 |
| - { |
1349 |
| - builder.AddContent(1, "I'm the final descendant"); |
1350 |
| - } |
| 1428 | + builder.AddContent(0, $"TreeParameter={TreeParameter}; RegularParameter={RegularParameter}"); |
1351 | 1429 | }
|
1352 | 1430 | }
|
1353 | 1431 | }
|
|
0 commit comments