From 949e86a2a9bae88c9527536f9d21adfe2994342f Mon Sep 17 00:00:00 2001 From: Mackinnon Buck Date: Thu, 9 Feb 2023 13:34:16 -0800 Subject: [PATCH 1/4] Introduce AddComponentParameter method --- .../Components/src/PublicAPI.Unshipped.txt | 4 ++- .../src/Rendering/RenderTreeBuilder.cs | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/Components/Components/src/PublicAPI.Unshipped.txt b/src/Components/Components/src/PublicAPI.Unshipped.txt index 34aa8535011c..ca1af7d2da0a 100644 --- a/src/Components/Components/src/PublicAPI.Unshipped.txt +++ b/src/Components/Components/src/PublicAPI.Unshipped.txt @@ -2,4 +2,6 @@ Microsoft.AspNetCore.Components.ComponentBase.DispatchExceptionAsync(System.Exception! exception) -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Components.RenderHandle.DispatchExceptionAsync(System.Exception! exception) -> System.Threading.Tasks.Task! *REMOVED*Microsoft.AspNetCore.Components.NavigationManager.ToAbsoluteUri(string! relativeUri) -> System.Uri! -Microsoft.AspNetCore.Components.NavigationManager.ToAbsoluteUri(string? relativeUri) -> System.Uri! \ No newline at end of file +Microsoft.AspNetCore.Components.NavigationManager.ToAbsoluteUri(string? relativeUri) -> System.Uri! +Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder.AddComponentParameter(int sequence, string! name, bool value) -> void +Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder.AddComponentParameter(int sequence, string! name, object? value) -> void \ No newline at end of file diff --git a/src/Components/Components/src/Rendering/RenderTreeBuilder.cs b/src/Components/Components/src/Rendering/RenderTreeBuilder.cs index c73277b706a5..7db3d8f7f6c7 100644 --- a/src/Components/Components/src/Rendering/RenderTreeBuilder.cs +++ b/src/Components/Components/src/Rendering/RenderTreeBuilder.cs @@ -505,6 +505,30 @@ public void OpenComponent(int sequence, [DynamicallyAccessedMembers(Component)] OpenComponentUnchecked(sequence, componentType); } + /// + /// Appends a frame representing a component parameter. + /// + /// An integer that represents the position of the instruction in the source code. + /// The name of the attribute. + /// The value of the attribute. + public void AddComponentParameter(int sequence, string name, bool value) + { + AssertCanAddComponentParameter(); + _entries.AppendAttribute(sequence, name, value ? BoxedTrue : BoxedFalse); + } + + /// + /// Appends a frame representing a component parameter. + /// + /// An integer that represents the position of the instruction in the source code. + /// The name of the attribute. + /// The value of the attribute. + public void AddComponentParameter(int sequence, string name, object? value) + { + AssertCanAddComponentParameter(); + _entries.AppendAttribute(sequence, name, value); + } + /// /// Assigns the specified key value to the current element or component. /// @@ -649,6 +673,14 @@ private void AssertCanAddAttribute() } } + private void AssertCanAddComponentParameter() + { + if (_lastNonAttributeFrameType != RenderTreeFrameType.Component) + { + throw new InvalidOperationException($"Component parameters may only be added immediately after frames of type {RenderTreeFrameType.Component}"); + } + } + private int? GetCurrentParentFrameIndex() => _openElementIndices.Count == 0 ? (int?)null : _openElementIndices.Peek(); From fde4b8f0e15859a786c5f99256d8665e2b728598 Mon Sep 17 00:00:00 2001 From: Mackinnon Buck Date: Thu, 9 Feb 2023 13:36:47 -0800 Subject: [PATCH 2/4] Apply AddComponentParamter throughout codebase --- .../Authorization/src/AuthorizeRouteView.cs | 16 +- .../test/AuthorizeRouteViewTest.cs | 6 +- .../Authorization/test/AuthorizeViewTest.cs | 20 +-- .../test/CascadingAuthenticationStateTest.cs | 2 +- .../Components/src/DynamicComponent.cs | 2 +- src/Components/Components/src/LayoutView.cs | 2 +- src/Components/Components/src/RouteView.cs | 6 +- .../Routing/QueryParameterValueSupplier.cs | 4 +- .../Components/test/CascadingParameterTest.cs | 56 +++---- .../test/ParameterViewTest.Assignment.cs | 2 +- .../test/RenderTreeDiffBuilderTest.cs | 62 +++---- .../Components/test/RendererTest.cs | 152 +++++++++--------- src/Components/Web/src/Forms/EditForm.cs | 6 +- .../Web/src/Forms/InputRadioGroup.cs | 4 +- src/Components/Web/src/Head/HeadContent.cs | 4 +- src/Components/Web/src/Head/HeadOutlet.cs | 10 +- src/Components/Web/src/Head/PageTitle.cs | 4 +- src/Components/Web/test/Forms/EditFormTest.cs | 4 +- .../Web/test/Forms/InputRadioTest.cs | 16 +- .../Web/test/Forms/TestInputHostComponent.cs | 10 +- .../Web/test/Virtualization/VirtualizeTest.cs | 6 +- 21 files changed, 197 insertions(+), 197 deletions(-) diff --git a/src/Components/Authorization/src/AuthorizeRouteView.cs b/src/Components/Authorization/src/AuthorizeRouteView.cs index 0fc33a242c01..f44afadff3ea 100644 --- a/src/Components/Authorization/src/AuthorizeRouteView.cs +++ b/src/Components/Authorization/src/AuthorizeRouteView.cs @@ -79,7 +79,7 @@ protected override void Render(RenderTreeBuilder builder) { // Otherwise, implicitly wrap the output in a builder.OpenComponent(0); - builder.AddAttribute(1, nameof(CascadingAuthenticationState.ChildContent), _renderAuthorizeRouteViewCoreDelegate); + builder.AddComponentParameter(1, nameof(CascadingAuthenticationState.ChildContent), _renderAuthorizeRouteViewCoreDelegate); builder.CloseComponent(); } } @@ -87,11 +87,11 @@ protected override void Render(RenderTreeBuilder builder) private void RenderAuthorizeRouteViewCore(RenderTreeBuilder builder) { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(AuthorizeRouteViewCore.RouteData), RouteData); - builder.AddAttribute(2, nameof(AuthorizeRouteViewCore.Authorized), _renderAuthorizedDelegate); - builder.AddAttribute(3, nameof(AuthorizeRouteViewCore.Authorizing), _renderAuthorizingDelegate); - builder.AddAttribute(4, nameof(AuthorizeRouteViewCore.NotAuthorized), _renderNotAuthorizedDelegate); - builder.AddAttribute(5, nameof(AuthorizeRouteViewCore.Resource), Resource); + builder.AddComponentParameter(1, nameof(AuthorizeRouteViewCore.RouteData), RouteData); + builder.AddComponentParameter(2, nameof(AuthorizeRouteViewCore.Authorized), _renderAuthorizedDelegate); + builder.AddComponentParameter(3, nameof(AuthorizeRouteViewCore.Authorizing), _renderAuthorizingDelegate); + builder.AddComponentParameter(4, nameof(AuthorizeRouteViewCore.NotAuthorized), _renderNotAuthorizedDelegate); + builder.AddComponentParameter(5, nameof(AuthorizeRouteViewCore.Resource), Resource); builder.CloseComponent(); } @@ -104,8 +104,8 @@ private void RenderAuthorizeRouteViewCore(RenderTreeBuilder builder) private void RenderContentInDefaultLayout(RenderTreeBuilder builder, RenderFragment content) { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(LayoutView.Layout), DefaultLayout); - builder.AddAttribute(2, nameof(LayoutView.ChildContent), content); + builder.AddComponentParameter(1, nameof(LayoutView.Layout), DefaultLayout); + builder.AddComponentParameter(2, nameof(LayoutView.ChildContent), content); builder.CloseComponent(); } diff --git a/src/Components/Authorization/test/AuthorizeRouteViewTest.cs b/src/Components/Authorization/test/AuthorizeRouteViewTest.cs index 8241cd54178b..98fc3d60b60b 100644 --- a/src/Components/Authorization/test/AuthorizeRouteViewTest.cs +++ b/src/Components/Authorization/test/AuthorizeRouteViewTest.cs @@ -411,11 +411,11 @@ public AuthorizeRouteViewWithExistingCascadedAuthenticationState( protected override void BuildRenderTree(RenderTreeBuilder builder) { builder.OpenComponent>>(0); - builder.AddAttribute(1, nameof(CascadingValue.Value), _authenticationState); - builder.AddAttribute(2, nameof(CascadingValue.ChildContent), (RenderFragment)(builder => + builder.AddComponentParameter(1, nameof(CascadingValue.Value), _authenticationState); + builder.AddComponentParameter(2, nameof(CascadingValue.ChildContent), (RenderFragment)(builder => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(AuthorizeRouteView.RouteData), _routeData); + builder.AddComponentParameter(1, nameof(AuthorizeRouteView.RouteData), _routeData); builder.CloseComponent(); })); builder.CloseComponent(); diff --git a/src/Components/Authorization/test/AuthorizeViewTest.cs b/src/Components/Authorization/test/AuthorizeViewTest.cs index 708f3ea6bb83..d31f84d83210 100644 --- a/src/Components/Authorization/test/AuthorizeViewTest.cs +++ b/src/Components/Authorization/test/AuthorizeViewTest.cs @@ -505,13 +505,13 @@ private static TestAuthStateProviderComponent WrapInAuthorizeView( return new TestAuthStateProviderComponent(builder => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(AuthorizeView.ChildContent), childContent); - builder.AddAttribute(2, nameof(AuthorizeView.Authorized), authorized); - builder.AddAttribute(3, nameof(AuthorizeView.NotAuthorized), notAuthorized); - builder.AddAttribute(4, nameof(AuthorizeView.Authorizing), authorizing); - builder.AddAttribute(5, nameof(AuthorizeView.Policy), policy); - builder.AddAttribute(6, nameof(AuthorizeView.Roles), roles); - builder.AddAttribute(7, nameof(AuthorizeView.Resource), resource); + builder.AddComponentParameter(1, nameof(AuthorizeView.ChildContent), childContent); + builder.AddComponentParameter(2, nameof(AuthorizeView.Authorized), authorized); + builder.AddComponentParameter(3, nameof(AuthorizeView.NotAuthorized), notAuthorized); + builder.AddComponentParameter(4, nameof(AuthorizeView.Authorizing), authorizing); + builder.AddComponentParameter(5, nameof(AuthorizeView.Policy), policy); + builder.AddComponentParameter(6, nameof(AuthorizeView.Roles), roles); + builder.AddComponentParameter(7, nameof(AuthorizeView.Resource), resource); builder.CloseComponent(); }); } @@ -531,11 +531,11 @@ public TestAuthStateProviderComponent(RenderFragment childContent) protected override void BuildRenderTree(RenderTreeBuilder builder) { builder.OpenComponent>>(0); - builder.AddAttribute(1, nameof(CascadingValue>.Value), AuthenticationState); - builder.AddAttribute(2, "ChildContent", (RenderFragment)(builder => + builder.AddComponentParameter(1, nameof(CascadingValue>.Value), AuthenticationState); + builder.AddComponentParameter(2, "ChildContent", (RenderFragment)(builder => { builder.OpenComponent(0); - builder.AddAttribute(1, "ChildContent", _childContent); + builder.AddComponentParameter(1, "ChildContent", _childContent); builder.CloseComponent(); })); builder.CloseComponent(); diff --git a/src/Components/Authorization/test/CascadingAuthenticationStateTest.cs b/src/Components/Authorization/test/CascadingAuthenticationStateTest.cs index 7effec50a2e0..020abf598046 100644 --- a/src/Components/Authorization/test/CascadingAuthenticationStateTest.cs +++ b/src/Components/Authorization/test/CascadingAuthenticationStateTest.cs @@ -177,7 +177,7 @@ class UseCascadingAuthenticationStateComponent : AutoRenderComponent protected override void BuildRenderTree(RenderTreeBuilder builder) { builder.OpenComponent(0); - builder.AddAttribute(1, "ChildContent", new RenderFragment(childBuilder => + builder.AddComponentParameter(1, "ChildContent", new RenderFragment(childBuilder => { childBuilder.OpenComponent(0); childBuilder.CloseComponent(); diff --git a/src/Components/Components/src/DynamicComponent.cs b/src/Components/Components/src/DynamicComponent.cs index 35252350bb84..974fb1452b16 100644 --- a/src/Components/Components/src/DynamicComponent.cs +++ b/src/Components/Components/src/DynamicComponent.cs @@ -98,7 +98,7 @@ void Render(RenderTreeBuilder builder) { foreach (var entry in Parameters) { - builder.AddAttribute(1, entry.Key, entry.Value); + builder.AddComponentParameter(1, entry.Key, entry.Value); } } diff --git a/src/Components/Components/src/LayoutView.cs b/src/Components/Components/src/LayoutView.cs index 60fa323cd91b..7e198bda8e0f 100644 --- a/src/Components/Components/src/LayoutView.cs +++ b/src/Components/Components/src/LayoutView.cs @@ -69,7 +69,7 @@ private static RenderFragment WrapInLayout([DynamicallyAccessedMembers(Component void Render(RenderTreeBuilder builder) { builder.OpenComponent(0, layoutType); - builder.AddAttribute(1, LayoutComponentBase.BodyPropertyName, bodyParam); + builder.AddComponentParameter(1, LayoutComponentBase.BodyPropertyName, bodyParam); builder.CloseComponent(); }; diff --git a/src/Components/Components/src/RouteView.cs b/src/Components/Components/src/RouteView.cs index 349060c1e6a3..d5e7df552d4b 100644 --- a/src/Components/Components/src/RouteView.cs +++ b/src/Components/Components/src/RouteView.cs @@ -81,8 +81,8 @@ protected virtual void Render(RenderTreeBuilder builder) ?? DefaultLayout; builder.OpenComponent(0); - builder.AddAttribute(1, nameof(LayoutView.Layout), pageLayoutType); - builder.AddAttribute(2, nameof(LayoutView.ChildContent), _renderPageWithParametersDelegate); + builder.AddComponentParameter(1, nameof(LayoutView.Layout), pageLayoutType); + builder.AddComponentParameter(2, nameof(LayoutView.ChildContent), _renderPageWithParametersDelegate); builder.CloseComponent(); } @@ -92,7 +92,7 @@ private void RenderPageWithParameters(RenderTreeBuilder builder) foreach (var kvp in RouteData.RouteValues) { - builder.AddAttribute(1, kvp.Key, kvp.Value); + builder.AddComponentParameter(1, kvp.Key, kvp.Value); } var queryParameterSupplier = QueryParameterValueSupplier.ForType(RouteData.PageType); diff --git a/src/Components/Components/src/Routing/QueryParameterValueSupplier.cs b/src/Components/Components/src/Routing/QueryParameterValueSupplier.cs index 40ae03126c1b..b217d09878ff 100644 --- a/src/Components/Components/src/Routing/QueryParameterValueSupplier.cs +++ b/src/Components/Components/src/Routing/QueryParameterValueSupplier.cs @@ -58,7 +58,7 @@ public void RenderParametersFromQueryString(RenderTreeBuilder builder, ReadOnlyM { ref var destination = ref _destinations[destinationIndex]; var blankValue = destination.IsArray ? destination.Parser.ParseMultiple(default, string.Empty) : null; - builder.AddAttribute(0, destination.ComponentParameterName, blankValue); + builder.AddComponentParameter(0, destination.ComponentParameterName, blankValue); } return; } @@ -101,7 +101,7 @@ public void RenderParametersFromQueryString(RenderTreeBuilder builder, ReadOnlyM ? default : destination.Parser.Parse(values[0].Span, destination.ComponentParameterName); - builder.AddAttribute(0, destination.ComponentParameterName, parsedValue); + builder.AddComponentParameter(0, destination.ComponentParameterName, parsedValue); } } finally diff --git a/src/Components/Components/test/CascadingParameterTest.cs b/src/Components/Components/test/CascadingParameterTest.cs index 9d82105a0557..0330b92fede7 100644 --- a/src/Components/Components/test/CascadingParameterTest.cs +++ b/src/Components/Components/test/CascadingParameterTest.cs @@ -17,11 +17,11 @@ public void PassesCascadingParametersToNestedComponents() var component = new TestComponent(builder => { builder.OpenComponent>(0); - builder.AddAttribute(1, "Value", "Hello"); - builder.AddAttribute(2, "ChildContent", new RenderFragment(childBuilder => + builder.AddComponentParameter(1, "Value", "Hello"); + builder.AddComponentParameter(2, "ChildContent", new RenderFragment(childBuilder => { childBuilder.OpenComponent>(0); - childBuilder.AddAttribute(1, "RegularParameter", "Goodbye"); + childBuilder.AddComponentParameter(1, "RegularParameter", "Goodbye"); childBuilder.CloseComponent(); })); builder.CloseComponent(); @@ -55,11 +55,11 @@ public void RetainsCascadingParametersWhenUpdatingDirectParameters() var component = new TestComponent(builder => { builder.OpenComponent>(0); - builder.AddAttribute(1, "Value", "Hello"); - builder.AddAttribute(2, "ChildContent", new RenderFragment(childBuilder => + builder.AddComponentParameter(1, "Value", "Hello"); + builder.AddComponentParameter(2, "ChildContent", new RenderFragment(childBuilder => { childBuilder.OpenComponent>(0); - childBuilder.AddAttribute(1, "RegularParameter", regularParameterValue); + childBuilder.AddComponentParameter(1, "RegularParameter", regularParameterValue); childBuilder.CloseComponent(); })); builder.CloseComponent(); @@ -103,11 +103,11 @@ public void NotifiesDescendantsOfUpdatedCascadingParameterValuesAndPreservesDire var component = new TestComponent(builder => { builder.OpenComponent>(0); - builder.AddAttribute(1, "Value", providedValue); - builder.AddAttribute(2, "ChildContent", new RenderFragment(childBuilder => + builder.AddComponentParameter(1, "Value", providedValue); + builder.AddComponentParameter(2, "ChildContent", new RenderFragment(childBuilder => { childBuilder.OpenComponent>(0); - childBuilder.AddAttribute(1, "RegularParameter", "Goodbye"); + childBuilder.AddComponentParameter(1, "RegularParameter", "Goodbye"); childBuilder.CloseComponent(); })); builder.CloseComponent(); @@ -148,11 +148,11 @@ public void DoesNotNotifyDescendantsIfCascadingParameterValuesAreImmutableAndUnc var component = new TestComponent(builder => { builder.OpenComponent>(0); - builder.AddAttribute(1, "Value", "Unchanging value"); - builder.AddAttribute(2, "ChildContent", new RenderFragment(childBuilder => + builder.AddComponentParameter(1, "Value", "Unchanging value"); + builder.AddComponentParameter(2, "ChildContent", new RenderFragment(childBuilder => { childBuilder.OpenComponent>(0); - childBuilder.AddAttribute(1, "RegularParameter", "Goodbye"); + childBuilder.AddComponentParameter(1, "RegularParameter", "Goodbye"); childBuilder.CloseComponent(); })); builder.CloseComponent(); @@ -187,19 +187,19 @@ public void StopsNotifyingDescendantsIfTheyAreRemoved() { // At the outer level, have an unrelated fixed cascading value to show we can deal with combining both types builder.OpenComponent>(0); - builder.AddAttribute(1, "Value", 123); - builder.AddAttribute(2, "IsFixed", true); - builder.AddAttribute(3, "ChildContent", new RenderFragment(builder2 => + builder.AddComponentParameter(1, "Value", 123); + builder.AddComponentParameter(2, "IsFixed", true); + builder.AddComponentParameter(3, "ChildContent", new RenderFragment(builder2 => { // Then also have a non-fixed cascading value so we can show that unsubscription works builder2.OpenComponent>(0); - builder2.AddAttribute(1, "Value", providedValue); - builder2.AddAttribute(2, "ChildContent", new RenderFragment(builder3 => + builder2.AddComponentParameter(1, "Value", providedValue); + builder2.AddComponentParameter(2, "ChildContent", new RenderFragment(builder3 => { if (displayNestedComponent) { builder3.OpenComponent>(0); - builder3.AddAttribute(1, "RegularParameter", "Goodbye"); + builder3.AddComponentParameter(1, "RegularParameter", "Goodbye"); builder3.CloseComponent(); } })); @@ -253,14 +253,14 @@ public void DoesNotNotifyDescendantsOfUpdatedCascadingParameterValuesWhenFixed() var component = new TestComponent(builder => { builder.OpenComponent>(0); - builder.AddAttribute(1, "Value", providedValue); - builder.AddAttribute(2, "IsFixed", true); - builder.AddAttribute(3, "ChildContent", new RenderFragment(childBuilder => + builder.AddComponentParameter(1, "Value", providedValue); + builder.AddComponentParameter(2, "IsFixed", true); + builder.AddComponentParameter(3, "ChildContent", new RenderFragment(childBuilder => { if (shouldIncludeChild) { childBuilder.OpenComponent>(0); - childBuilder.AddAttribute(1, "RegularParameter", "Goodbye"); + childBuilder.AddComponentParameter(1, "RegularParameter", "Goodbye"); childBuilder.CloseComponent(); } })); @@ -312,8 +312,8 @@ public void CascadingValueThrowsIfFixedFlagChangesToTrue() var component = new TestComponent(builder => { builder.OpenComponent>(0); - builder.AddAttribute(1, "IsFixed", isFixed); - builder.AddAttribute(2, "Value", new object()); + builder.AddComponentParameter(1, "IsFixed", isFixed); + builder.AddComponentParameter(2, "Value", new object()); builder.CloseComponent(); }); renderer.AssignRootComponentId(component); @@ -336,9 +336,9 @@ public void CascadingValueThrowsIfFixedFlagChangesToFalse() builder.OpenComponent>(0); if (isFixed) // Showing also that "unset" is treated as "false" { - builder.AddAttribute(1, "IsFixed", true); + builder.AddComponentParameter(1, "IsFixed", true); } - builder.AddAttribute(2, "Value", new object()); + builder.AddComponentParameter(2, "Value", new object()); builder.CloseComponent(); }); renderer.AssignRootComponentId(component); @@ -359,8 +359,8 @@ public void ParameterViewSuppliedWithCascadingParametersCannotBeUsedAfterSynchro var component = new TestComponent(builder => { builder.OpenComponent>(0); - builder.AddAttribute(1, "Value", providedValue); - builder.AddAttribute(2, "ChildContent", new RenderFragment(childBuilder => + builder.AddComponentParameter(1, "Value", providedValue); + builder.AddComponentParameter(2, "ChildContent", new RenderFragment(childBuilder => { childBuilder.OpenComponent>(0); childBuilder.CloseComponent(); diff --git a/src/Components/Components/test/ParameterViewTest.Assignment.cs b/src/Components/Components/test/ParameterViewTest.Assignment.cs index 5c7f8a174835..8fff5c2003d0 100644 --- a/src/Components/Components/test/ParameterViewTest.Assignment.cs +++ b/src/Components/Components/test/ParameterViewTest.Assignment.cs @@ -664,7 +664,7 @@ public ParameterView Build() { if (!kvp.Cascading) { - builder.AddAttribute(1, kvp.Name, kvp.Value); + builder.AddComponentParameter(1, kvp.Name, kvp.Value); } } builder.CloseComponent(); diff --git a/src/Components/Components/test/RenderTreeDiffBuilderTest.cs b/src/Components/Components/test/RenderTreeDiffBuilderTest.cs index 613ddc665bea..a11596169fa4 100644 --- a/src/Components/Components/test/RenderTreeDiffBuilderTest.cs +++ b/src/Components/Components/test/RenderTreeDiffBuilderTest.cs @@ -210,7 +210,7 @@ public void RecognizesKeyedComponentInsertions() // Arrange oldTree.OpenComponent(0); oldTree.SetKey("retained key"); - oldTree.AddAttribute(1, "ParamName", "Param old value"); + oldTree.AddComponentParameter(1, "ParamName", "Param old value"); oldTree.CloseComponent(); using var initial = new RenderTreeBuilder(); GetRenderedBatch(initial, oldTree, false); // Assign initial IDs @@ -218,12 +218,12 @@ public void RecognizesKeyedComponentInsertions() newTree.OpenComponent(0); newTree.SetKey("new key"); - newTree.AddAttribute(1, "ParamName", "New component param value"); + newTree.AddComponentParameter(1, "ParamName", "New component param value"); newTree.CloseComponent(); newTree.OpenComponent(0); newTree.SetKey("retained key"); - newTree.AddAttribute(1, "ParamName", "Param new value"); + newTree.AddComponentParameter(1, "ParamName", "Param new value"); newTree.CloseComponent(); // Without the key, it would modify the param on the first component, @@ -251,12 +251,12 @@ public void RecognizesKeyedComponentDeletions() // Arrange oldTree.OpenComponent(0); oldTree.SetKey("will delete"); - oldTree.AddAttribute(1, nameof(FakeComponent.StringProperty), "Anything"); + oldTree.AddComponentParameter(1, nameof(FakeComponent.StringProperty), "Anything"); oldTree.CloseComponent(); oldTree.OpenComponent(0); oldTree.SetKey("will retain"); - oldTree.AddAttribute(1, nameof(FakeComponent.StringProperty), "Retained param value"); + oldTree.AddComponentParameter(1, nameof(FakeComponent.StringProperty), "Retained param value"); oldTree.CloseComponent(); // Instantiate initial components @@ -266,7 +266,7 @@ public void RecognizesKeyedComponentDeletions() newTree.OpenComponent(0); newTree.SetKey("will retain"); - newTree.AddAttribute(1, nameof(FakeComponent.StringProperty), "Retained param value"); + newTree.AddComponentParameter(1, nameof(FakeComponent.StringProperty), "Retained param value"); newTree.CloseComponent(); // Without the key, it updates the param on the first component, then @@ -289,11 +289,11 @@ public void RecognizesKeyedComponentDeletionsBeforeUnchangedNonKeyedComponent() // Arrange oldTree.OpenComponent(0); oldTree.SetKey("will delete"); - oldTree.AddAttribute(1, nameof(FakeComponent.StringProperty), "Will delete"); + oldTree.AddComponentParameter(1, nameof(FakeComponent.StringProperty), "Will delete"); oldTree.CloseComponent(); oldTree.OpenComponent(2); - oldTree.AddAttribute(3, nameof(FakeComponent.StringProperty), "Retained param value"); + oldTree.AddComponentParameter(3, nameof(FakeComponent.StringProperty), "Retained param value"); oldTree.CloseComponent(); // Instantiate initial components @@ -302,7 +302,7 @@ public void RecognizesKeyedComponentDeletionsBeforeUnchangedNonKeyedComponent() var oldComponents = GetComponents(oldTree); newTree.OpenComponent(2); - newTree.AddAttribute(3, nameof(FakeComponent.StringProperty), "Retained param value"); + newTree.AddComponentParameter(3, nameof(FakeComponent.StringProperty), "Retained param value"); newTree.CloseComponent(); // Act @@ -1587,9 +1587,9 @@ public void SetsParametersOnChildComponents() // Arrange var testObject = new object(); newTree.OpenComponent(0); - newTree.AddAttribute(1, nameof(FakeComponent.IntProperty), 123); - newTree.AddAttribute(2, nameof(FakeComponent.StringProperty), "some string"); - newTree.AddAttribute(3, nameof(FakeComponent.ObjectProperty), testObject); + newTree.AddComponentParameter(1, nameof(FakeComponent.IntProperty), 123); + newTree.AddComponentParameter(2, nameof(FakeComponent.StringProperty), "some string"); + newTree.AddComponentParameter(3, nameof(FakeComponent.ObjectProperty), testObject); newTree.CloseComponent(); // Act @@ -1703,12 +1703,12 @@ public void SetsUpdatedParametersOnChildComponents() // Arrange var objectWillNotChange = new object(); oldTree.OpenComponent(12); - oldTree.AddAttribute(13, nameof(FakeComponent.StringProperty), "String will change"); - oldTree.AddAttribute(14, nameof(FakeComponent.ObjectProperty), objectWillNotChange); + oldTree.AddComponentParameter(13, nameof(FakeComponent.StringProperty), "String will change"); + oldTree.AddComponentParameter(14, nameof(FakeComponent.ObjectProperty), objectWillNotChange); oldTree.CloseComponent(); newTree.OpenComponent(12); - newTree.AddAttribute(13, nameof(FakeComponent.StringProperty), "String did change"); - newTree.AddAttribute(14, nameof(FakeComponent.ObjectProperty), objectWillNotChange); + newTree.AddComponentParameter(13, nameof(FakeComponent.StringProperty), "String did change"); + newTree.AddComponentParameter(14, nameof(FakeComponent.ObjectProperty), objectWillNotChange); newTree.CloseComponent(); using var batchBuilder = new RenderBatchBuilder(); @@ -1739,16 +1739,16 @@ public void SkipsUpdatingParametersOnChildComponentsIfAllAreDefinitelyImmutableA foreach (var tree in new[] { oldTree, newTree }) { tree.OpenComponent(0); - tree.AddAttribute(1, "MyString", "Some fixed string"); - tree.AddAttribute(1, "MyByte", (byte)123); - tree.AddAttribute(1, "MyInt", int.MaxValue); - tree.AddAttribute(1, "MyLong", long.MaxValue); - tree.AddAttribute(1, "MyBool", true); - tree.AddAttribute(1, "MyFloat", float.MaxValue); - tree.AddAttribute(1, "MyDouble", double.MaxValue); - tree.AddAttribute(1, "MyDecimal", decimal.MinusOne); - tree.AddAttribute(1, "MyDate", dateTimeWillNotChange); - tree.AddAttribute(1, "MyGuid", Guid.Empty); + tree.AddComponentParameter(1, "MyString", "Some fixed string"); + tree.AddComponentParameter(1, "MyByte", (byte)123); + tree.AddComponentParameter(1, "MyInt", int.MaxValue); + tree.AddComponentParameter(1, "MyLong", long.MaxValue); + tree.AddComponentParameter(1, "MyBool", true); + tree.AddComponentParameter(1, "MyFloat", float.MaxValue); + tree.AddComponentParameter(1, "MyDouble", double.MaxValue); + tree.AddComponentParameter(1, "MyDecimal", decimal.MinusOne); + tree.AddComponentParameter(1, "MyDate", dateTimeWillNotChange); + tree.AddComponentParameter(1, "MyGuid", Guid.Empty); tree.CloseComponent(); } @@ -1778,7 +1778,7 @@ public void AlwaysRegardsRenderFragmentAsPossiblyChanged() foreach (var tree in new[] { oldTree, newTree }) { tree.OpenComponent(0); - tree.AddAttribute(1, "MyFragment", fragmentWillNotChange); + tree.AddComponentParameter(1, "MyFragment", fragmentWillNotChange); tree.CloseComponent(); } @@ -2009,14 +2009,14 @@ public void RecognizesKeyedComponentMoves() // Arrange oldTree.OpenComponent(0); oldTree.SetKey("first key"); - oldTree.AddAttribute(1, nameof(FakeComponent.StringProperty), "First param"); + oldTree.AddComponentParameter(1, nameof(FakeComponent.StringProperty), "First param"); oldTree.CloseComponent(); oldTree.AddContent(2, "Unkeyed item"); oldTree.OpenComponent(0); oldTree.SetKey("second key"); - oldTree.AddAttribute(1, nameof(FakeComponent.StringProperty), "Second param"); + oldTree.AddComponentParameter(1, nameof(FakeComponent.StringProperty), "Second param"); oldTree.CloseComponent(); using var renderTreeBuilder = new RenderTreeBuilder(); @@ -2025,14 +2025,14 @@ public void RecognizesKeyedComponentMoves() newTree.OpenComponent(0); newTree.SetKey("second key"); - newTree.AddAttribute(1, nameof(FakeComponent.StringProperty), "Second param"); + newTree.AddComponentParameter(1, nameof(FakeComponent.StringProperty), "Second param"); newTree.CloseComponent(); newTree.AddContent(2, "Unkeyed item"); newTree.OpenComponent(0); newTree.SetKey("first key"); - newTree.AddAttribute(1, nameof(FakeComponent.StringProperty), "First param modified"); + newTree.AddComponentParameter(1, nameof(FakeComponent.StringProperty), "First param modified"); newTree.CloseComponent(); // Without the key, it changes the parameter on both diff --git a/src/Components/Components/test/RendererTest.cs b/src/Components/Components/test/RendererTest.cs index 6816812c8713..5b4005798e39 100644 --- a/src/Components/Components/test/RendererTest.cs +++ b/src/Components/Components/test/RendererTest.cs @@ -63,7 +63,7 @@ public void CanRenderNestedComponents() { builder.AddContent(0, "Hello"); builder.OpenComponent(1); - builder.AddAttribute(2, nameof(MessageComponent.Message), "Nested component output"); + builder.AddComponentParameter(2, nameof(MessageComponent.Message), "Nested component output"); builder.CloseComponent(); }); @@ -1018,7 +1018,7 @@ public async Task EventDispatching_DelegateParameter_MethodToDelegateConversion( parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickAction), (Action)parentComponent.SomeMethod); + builder.AddComponentParameter(1, nameof(EventComponent.OnClickAction), (Action)parentComponent.SomeMethod); builder.CloseComponent(); }; parentComponent.OnEvent = () => @@ -1059,7 +1059,7 @@ public async Task EventDispatching_DelegateParameter_NoTargetLambda() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickAction), (Action)(() => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickAction), (Action)(() => { parentComponent.SomeMethod(); })); @@ -1101,7 +1101,7 @@ public async Task EventDispatching_EventCallback_MethodToDelegateConversion() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, (Action)parentComponent.SomeMethod)); + builder.AddComponentParameter(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, (Action)parentComponent.SomeMethod)); builder.CloseComponent(); }; parentComponent.OnEvent = () => @@ -1139,7 +1139,7 @@ public async Task EventDispatching_EventCallback_NoTargetLambda() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, (Action)(() => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, (Action)(() => { parentComponent.SomeMethod(); }))); @@ -1180,7 +1180,7 @@ public async Task EventDispatching_EventCallback_AsyncNoTargetLambda() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, (Func)(() => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, (Func)(() => { parentComponent.SomeMethod(); return Task.CompletedTask; @@ -1220,7 +1220,7 @@ public async Task EventDispatching_EventCallbackOfT_MethodToDelegateConversion() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, (Action)parentComponent.SomeMethod)); + builder.AddComponentParameter(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, (Action)parentComponent.SomeMethod)); builder.CloseComponent(); }; parentComponent.OnEvent = () => @@ -1258,7 +1258,7 @@ public async Task EventDispatching_EventCallbackOfT_NoTargetLambda() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, (Action)(() => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, (Action)(() => { parentComponent.SomeMethod(); }))); @@ -1299,7 +1299,7 @@ public async Task EventDispatching_EventCallbackOfT_AsyncNoTargetLambda() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, (Func)(() => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, (Func)(() => { parentComponent.SomeMethod(); return Task.CompletedTask; @@ -1337,7 +1337,7 @@ public async Task DispatchEventAsync_Delegate_SynchronousCompletion() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickAction), (Action)(() => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickAction), (Action)(() => { // Do nothing. })); @@ -1369,7 +1369,7 @@ public async Task DispatchEventAsync_EventCallback_SynchronousCompletion() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, (Action)(() => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, (Action)(() => { // Do nothing. }))); @@ -1403,7 +1403,7 @@ public async Task DispatchEventAsync_EventCallbackOfT_SynchronousCompletion() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, (Action)((e) => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, (Action)((e) => { arg = e; }))); @@ -1436,7 +1436,7 @@ public async Task DispatchEventAsync_Delegate_SynchronousCancellation() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickAction), (Action)(() => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickAction), (Action)(() => { throw new OperationCanceledException(); })); @@ -1468,7 +1468,7 @@ public async Task DispatchEventAsync_EventCallback_SynchronousCancellation() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, (Action)(() => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, (Action)(() => { throw new OperationCanceledException(); }))); @@ -1502,7 +1502,7 @@ public async Task DispatchEventAsync_EventCallbackOfT_SynchronousCancellation() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, (Action)((e) => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, (Action)((e) => { arg = e; throw new OperationCanceledException(); @@ -1536,7 +1536,7 @@ public async Task DispatchEventAsync_Delegate_SynchronousException() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickAction), (Action)(() => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickAction), (Action)(() => { throw new InvalidTimeZoneException(); })); @@ -1568,7 +1568,7 @@ public async Task DispatchEventAsync_EventCallback_SynchronousException() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, (Action)(() => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, (Action)(() => { throw new InvalidTimeZoneException(); }))); @@ -1602,7 +1602,7 @@ public async Task DispatchEventAsync_EventCallbackOfT_SynchronousException() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, (Action)((e) => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, (Action)((e) => { arg = e; throw new InvalidTimeZoneException(); @@ -1638,7 +1638,7 @@ public async Task DispatchEventAsync_Delegate_AsynchronousCompletion() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickAsyncAction), (Func)(async () => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickAsyncAction), (Func)(async () => { await tcs.Task; })); @@ -1673,7 +1673,7 @@ public async Task DispatchEventAsync_EventCallback_AsynchronousCompletion() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, async () => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, async () => { await tcs.Task; })); @@ -1710,7 +1710,7 @@ public async Task DispatchEventAsync_EventCallbackOfT_AsynchronousCompletion() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, async (e) => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, async (e) => { arg = e; await tcs.Task; @@ -1747,7 +1747,7 @@ public async Task DispatchEventAsync_Delegate_AsynchronousCancellation() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickAsyncAction), (Func)(async () => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickAsyncAction), (Func)(async () => { await tcs.Task; throw new TaskCanceledException(); @@ -1785,7 +1785,7 @@ public async Task DispatchEventAsync_EventCallback_AsynchronousCancellation() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, async () => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, async () => { await tcs.Task; throw new TaskCanceledException(); @@ -1825,7 +1825,7 @@ public async Task DispatchEventAsync_EventCallbackOfT_AsynchronousCancellation() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, async (e) => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, async (e) => { arg = e; await tcs.Task; @@ -1865,7 +1865,7 @@ public async Task DispatchEventAsync_Delegate_AsynchronousException() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickAsyncAction), (Func)(async () => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickAsyncAction), (Func)(async () => { await tcs.Task; throw new InvalidTimeZoneException(); @@ -1902,7 +1902,7 @@ public async Task DispatchEventAsync_EventCallback_AsynchronousException() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, async () => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickEventCallback), EventCallback.Factory.Create(parentComponent, async () => { await tcs.Task; throw new InvalidTimeZoneException(); @@ -1941,7 +1941,7 @@ public async Task DispatchEventAsync_EventCallbackOfT_AsynchronousException() parentComponent.RenderFragment = (builder) => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, async (e) => + builder.AddComponentParameter(1, nameof(EventComponent.OnClickEventCallbackOfT), EventCallback.Factory.Create(parentComponent, async (e) => { arg = e; await tcs.Task; @@ -2064,9 +2064,9 @@ public void UpdatesPropertiesOnRetainedChildComponentInstances() var component = new TestComponent(builder => { builder.OpenComponent(1); - builder.AddAttribute(2, nameof(FakeComponent.IntProperty), firstRender ? 123 : 256); - builder.AddAttribute(3, nameof(FakeComponent.ObjectProperty), objectThatWillNotChange); - builder.AddAttribute(4, nameof(FakeComponent.StringProperty), firstRender ? "String that will change" : "String that did change"); + builder.AddComponentParameter(2, nameof(FakeComponent.IntProperty), firstRender ? 123 : 256); + builder.AddComponentParameter(3, nameof(FakeComponent.ObjectProperty), objectThatWillNotChange); + builder.AddComponentParameter(4, nameof(FakeComponent.StringProperty), firstRender ? "String that will change" : "String that did change"); builder.CloseComponent(); }); @@ -2102,7 +2102,7 @@ public void ReRendersChildComponentsWhenPropertiesChange() var component = new TestComponent(builder => { builder.OpenComponent(1); - builder.AddAttribute(2, nameof(MessageComponent.Message), firstRender ? "first" : "second"); + builder.AddComponentParameter(2, nameof(MessageComponent.Message), firstRender ? "first" : "second"); builder.CloseComponent(); }); @@ -2138,9 +2138,9 @@ public void ReRendersChildComponentWhenUnmatchedValuesChange() var component = new TestComponent(builder => { builder.OpenComponent(1); - builder.AddAttribute(1, "class", firstRender ? "first" : "second"); - builder.AddAttribute(2, "id", "some_text"); - builder.AddAttribute(3, nameof(MyStrongComponent.Text), "hi there."); + builder.AddComponentParameter(1, "class", firstRender ? "first" : "second"); + builder.AddComponentParameter(2, "id", "some_text"); + builder.AddComponentParameter(3, nameof(MyStrongComponent.Text), "hi there."); builder.CloseComponent(); }); @@ -2178,9 +2178,9 @@ public void ReRendersDoesNotReRenderChildComponentWhenUnmatchedValuesDoNotChange var component = new TestComponent(builder => { builder.OpenComponent(1); - builder.AddAttribute(1, "class", "cool-beans"); - builder.AddAttribute(2, "id", "some_text"); - builder.AddAttribute(3, nameof(MyStrongComponent.Text), "hi there."); + builder.AddComponentParameter(1, "class", "cool-beans"); + builder.AddComponentParameter(2, "id", "some_text"); + builder.AddComponentParameter(3, nameof(MyStrongComponent.Text), "hi there."); builder.CloseComponent(); }); @@ -2211,7 +2211,7 @@ public void RenderBatchIncludesListOfDisposedComponents() { // Nested descendants builder.OpenComponent>(100); - builder.AddAttribute(101, nameof(ConditionalParentComponent.IncludeChild), true); + builder.AddComponentParameter(101, nameof(ConditionalParentComponent.IncludeChild), true); builder.CloseComponent(); } builder.OpenComponent(200); @@ -2265,11 +2265,11 @@ public void RenderBatch_HandlesExceptionsFromAllDisposedComponents() { builder.AddContent(0, "Hello"); builder.OpenComponent(1); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => throw exception1)); + builder.AddComponentParameter(1, nameof(DisposableComponent.DisposeAction), (Action)(() => throw exception1)); builder.CloseComponent(); builder.OpenComponent(2); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => throw exception2)); + builder.AddComponentParameter(1, nameof(DisposableComponent.DisposeAction), (Action)(() => throw exception2)); builder.CloseComponent(); } }); @@ -2305,7 +2305,7 @@ public void RenderBatch_HandlesSynchronousExceptionsInAsyncDisposableComponents( { builder.AddContent(0, "Hello"); builder.OpenComponent(1); - builder.AddAttribute(1, nameof(AsyncDisposableComponent.AsyncDisposeAction), (Func)(() => throw exception1)); + builder.AddComponentParameter(1, nameof(AsyncDisposableComponent.AsyncDisposeAction), (Func)(() => throw exception1)); builder.CloseComponent(); } }); @@ -2340,7 +2340,7 @@ public void RenderBatch_CanDisposeSynchronousAsyncDisposableImplementations() { builder.AddContent(0, "Hello"); builder.OpenComponent(1); - builder.AddAttribute(1, nameof(AsyncDisposableComponent.AsyncDisposeAction), (Func)(() => default)); + builder.AddComponentParameter(1, nameof(AsyncDisposableComponent.AsyncDisposeAction), (Func)(() => default)); builder.CloseComponent(); } }); @@ -2377,7 +2377,7 @@ public void RenderBatch_CanDisposeAsynchronousAsyncDisposables() { builder.AddContent(0, "Hello"); builder.OpenComponent(1); - builder.AddAttribute(1, nameof(AsyncDisposableComponent.AsyncDisposeAction), (Func)(async () => { await tcs.Task; })); + builder.AddComponentParameter(1, nameof(AsyncDisposableComponent.AsyncDisposeAction), (Func)(async () => { await tcs.Task; })); builder.CloseComponent(); } }); @@ -2419,7 +2419,7 @@ public void RenderBatch_HandlesAsynchronousExceptionsInAsyncDisposableComponents { builder.AddContent(0, "Hello"); builder.OpenComponent(1); - builder.AddAttribute(1, nameof(AsyncDisposableComponent.AsyncDisposeAction), (Func)(async () => { await tcs.Task; throw exception1; })); + builder.AddComponentParameter(1, nameof(AsyncDisposableComponent.AsyncDisposeAction), (Func)(async () => { await tcs.Task; throw exception1; })); builder.CloseComponent(); } }); @@ -2458,7 +2458,7 @@ public void RenderBatch_ReportsSynchronousCancelationsAsErrors() { builder.AddContent(0, "Hello"); builder.OpenComponent(1); - builder.AddAttribute(1, nameof(AsyncDisposableComponent.AsyncDisposeAction), (Func)(() => throw new TaskCanceledException())); + builder.AddComponentParameter(1, nameof(AsyncDisposableComponent.AsyncDisposeAction), (Func)(() => throw new TaskCanceledException())); builder.CloseComponent(); } }); @@ -2494,7 +2494,7 @@ public void RenderBatch_ReportsAsynchronousCancelationsAsErrors() { builder.AddContent(0, "Hello"); builder.OpenComponent(1); - builder.AddAttribute( + builder.AddComponentParameter( 1, nameof(AsyncDisposableComponent.AsyncDisposeAction), (Func)(() => new ValueTask(tcs.Task))); @@ -2544,24 +2544,24 @@ public void RenderBatch_DoesNotDisposeComponentMultipleTimes() { builder.AddContent(0, "Hello"); builder.OpenComponent(1); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => { count1++; })); + builder.AddComponentParameter(1, nameof(DisposableComponent.DisposeAction), (Action)(() => { count1++; })); builder.CloseComponent(); builder.OpenComponent(2); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => { count2++; throw exception1; })); + builder.AddComponentParameter(1, nameof(DisposableComponent.DisposeAction), (Action)(() => { count2++; throw exception1; })); builder.CloseComponent(); builder.OpenComponent(3); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => { count3++; })); + builder.AddComponentParameter(1, nameof(DisposableComponent.DisposeAction), (Action)(() => { count3++; })); builder.CloseComponent(); } builder.OpenComponent(4); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => { count4++; throw exception2; })); + builder.AddComponentParameter(1, nameof(DisposableComponent.DisposeAction), (Action)(() => { count4++; throw exception2; })); builder.CloseComponent(); builder.OpenComponent(5); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => { count5++; })); + builder.AddComponentParameter(1, nameof(DisposableComponent.DisposeAction), (Action)(() => { count5++; })); builder.CloseComponent(); }); var componentId = renderer.AssignRootComponentId(component); @@ -2779,7 +2779,7 @@ public async Task AllRendersTriggeredSynchronouslyDuringEventHandlerAreHandledAs { builder.AddContent(0, "Child event count: " + eventCount); builder.OpenComponent(1); - builder.AddAttribute(2, nameof(EventComponent.OnTest), new Action(args => + builder.AddComponentParameter(2, nameof(EventComponent.OnTest), new Action(args => { eventCount++; rootComponent.TriggerRender(); @@ -2901,7 +2901,7 @@ public void ComponentCanTriggerRenderWhenExistingBatchIsInProgress() parent = new TestComponent(builder => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(ReRendersParentComponent.Parent), parent); + builder.AddComponentParameter(1, nameof(ReRendersParentComponent.Parent), parent); builder.CloseComponent(); builder.AddContent(2, $"Parent render count: {++parentRenderCount}"); }); @@ -2967,7 +2967,7 @@ public void QueuedRenderIsSkippedIfComponentWasAlreadyDisposedInSameBatch() if (shouldRenderChild) { builder.OpenComponent(1); - builder.AddAttribute(2, "onclick", (Action)((object obj) => + builder.AddComponentParameter(2, "onclick", (Action)((object obj) => { // First we queue (1) a re-render of the root component, then the child component // will queue (2) its own re-render. But by the time (1) completes, the child will @@ -3329,7 +3329,7 @@ public void DoesNotCallOnAfterRenderForComponentsNotRendered() { // First child will be re-rendered because we'll change its param builder.OpenComponent(0); - builder.AddAttribute(1, "some param", showComponent3); + builder.AddComponentParameter(1, "some param", showComponent3); builder.CloseComponent(); // Second child will not be re-rendered because nothing changes @@ -3645,7 +3645,7 @@ public async Task ExceptionsThrownAsynchronouslyAfterFirstRenderCanBeHandled() var component = new TestComponent(builder => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(ComponentThatAwaitsTask.TaskToAwait), taskToAwait); + builder.AddComponentParameter(1, nameof(ComponentThatAwaitsTask.TaskToAwait), taskToAwait); builder.CloseComponent(); }); var componentId = renderer.AssignRootComponentId(component); @@ -4173,11 +4173,11 @@ public void DisposingRenderer_CapturesExceptionsFromAllRegisteredComponents() { builder.AddContent(0, "Hello"); builder.OpenComponent(1); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => throw exception1)); + builder.AddComponentParameter(1, nameof(DisposableComponent.DisposeAction), (Action)(() => throw exception1)); builder.CloseComponent(); builder.OpenComponent(2); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => throw exception2)); + builder.AddComponentParameter(1, nameof(DisposableComponent.DisposeAction), (Action)(() => throw exception2)); builder.CloseComponent(); }); var componentId = renderer.AssignRootComponentId(component); @@ -4205,7 +4205,7 @@ public async Task DisposingRenderer_CapturesSyncExceptionsFromAllRegisteredAsync { builder.AddContent(0, "Hello"); builder.OpenComponent(1); - builder.AddAttribute(1, nameof(AsyncDisposableComponent.AsyncDisposeAction), (Func)(() => { disposed = true; throw exception1; })); + builder.AddComponentParameter(1, nameof(AsyncDisposableComponent.AsyncDisposeAction), (Func)(() => { disposed = true; throw exception1; })); builder.CloseComponent(); }); var componentId = renderer.AssignRootComponentId(component); @@ -4233,7 +4233,7 @@ public async Task DisposingRenderer_CapturesAsyncExceptionsFromAllRegisteredAsyn { builder.AddContent(0, "Hello"); builder.OpenComponent(1); - builder.AddAttribute(1, nameof(AsyncDisposableComponent.AsyncDisposeAction), (Func)(async () => { await tcs.Task; disposed = true; throw exception1; })); + builder.AddComponentParameter(1, nameof(AsyncDisposableComponent.AsyncDisposeAction), (Func)(async () => { await tcs.Task; disposed = true; throw exception1; })); builder.CloseComponent(); }); var componentId = renderer.AssignRootComponentId(component); @@ -4381,7 +4381,7 @@ public void CannotAccessParameterViewAfterSynchronousReturn() var rootComponent = new TestComponent(builder => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(ParameterViewIllegalCapturingComponent.SomeParam), 0); + builder.AddComponentParameter(1, nameof(ParameterViewIllegalCapturingComponent.SomeParam), 0); builder.CloseComponent(); }); var rootComponentId = renderer.AssignRootComponentId(rootComponent); @@ -4468,7 +4468,7 @@ public void RenderingExceptionsCanBeHandledByClosestErrorBoundary() TestErrorBoundary.RenderNestedErrorBoundaries(builder, builder => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(ErrorThrowingComponent.ThrowDuringRender), exception); + builder.AddComponentParameter(1, nameof(ErrorThrowingComponent.ThrowDuringRender), exception); builder.CloseComponent(); }); })); @@ -4499,7 +4499,7 @@ public void SetParametersAsyncExceptionsCanBeHandledByClosestErrorBoundary_Sync( TestErrorBoundary.RenderNestedErrorBoundaries(builder, builder => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(ErrorThrowingComponent.ThrowDuringParameterSettingSync), exception); + builder.AddComponentParameter(1, nameof(ErrorThrowingComponent.ThrowDuringParameterSettingSync), exception); builder.CloseComponent(); }); }); @@ -4536,7 +4536,7 @@ public async Task SetParametersAsyncExceptionsCanBeHandledByClosestErrorBoundary TestErrorBoundary.RenderNestedErrorBoundaries(builder, builder => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(ErrorThrowingComponent.ThrowDuringParameterSettingAsync), exceptionTcs?.Task); + builder.AddComponentParameter(1, nameof(ErrorThrowingComponent.ThrowDuringParameterSettingAsync), exceptionTcs?.Task); builder.CloseComponent(); }); }); @@ -4575,7 +4575,7 @@ public void EventDispatchExceptionsCanBeHandledByClosestErrorBoundary_Sync() TestErrorBoundary.RenderNestedErrorBoundaries(builder, builder => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(ErrorThrowingComponent.ThrowDuringEventSync), exception); + builder.AddComponentParameter(1, nameof(ErrorThrowingComponent.ThrowDuringEventSync), exception); builder.CloseComponent(); }); })); @@ -4614,7 +4614,7 @@ public async Task EventDispatchExceptionsCanBeHandledByClosestErrorBoundary_Asyn TestErrorBoundary.RenderNestedErrorBoundaries(builder, builder => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(ErrorThrowingComponent.ThrowDuringEventAsync), exceptionTcs.Task); + builder.AddComponentParameter(1, nameof(ErrorThrowingComponent.ThrowDuringEventAsync), exceptionTcs.Task); builder.CloseComponent(); }); })); @@ -4661,7 +4661,7 @@ public async Task EventDispatchExceptionsCanBeHandledByClosestErrorBoundary_Afte TestErrorBoundary.RenderNestedErrorBoundaries(builder, builder => { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(ErrorThrowingComponent.ThrowDuringEventAsync), exceptionTcs.Task); + builder.AddComponentParameter(1, nameof(ErrorThrowingComponent.ThrowDuringEventAsync), exceptionTcs.Task); builder.CloseComponent(); }); } @@ -4820,11 +4820,11 @@ public void RemoveRootComponentHandlesDisposalExceptions() { builder.AddContent(0, "Hello"); builder.OpenComponent(1); - builder.AddAttribute(1, nameof(DisposableComponent.DisposeAction), (Action)(() => throw exception1)); + builder.AddComponentParameter(1, nameof(DisposableComponent.DisposeAction), (Action)(() => throw exception1)); builder.CloseComponent(); builder.OpenComponent(2); - builder.AddAttribute(1, nameof(AsyncDisposableComponent.AsyncDisposeAction), (Func)(async () => await exception2Tcs.Task)); + builder.AddComponentParameter(1, nameof(AsyncDisposableComponent.AsyncDisposeAction), (Func)(async () => await exception2Tcs.Task)); builder.CloseComponent(); }); var rootComponentId = renderer.AssignRootComponentId(rootComponent); @@ -5176,7 +5176,7 @@ protected override void BuildRenderTree(RenderTreeBuilder builder) { foreach (var kvp in ChildParameters) { - builder.AddAttribute(2, kvp.Key, kvp.Value); + builder.AddComponentParameter(2, kvp.Key, kvp.Value); } } builder.CloseComponent(); @@ -5477,10 +5477,10 @@ private Func CreateRenderFactory(int[] chi foreach (var child in childrenToRender) { builder.OpenComponent(2); - builder.AddAttribute(3, eventActionsName, component.EventActions); - builder.AddAttribute(4, whatToRenderName, component.WhatToRender); - builder.AddAttribute(5, testIdName, child); - builder.AddAttribute(6, logName, component.Log); + builder.AddComponentParameter(3, eventActionsName, component.EventActions); + builder.AddComponentParameter(4, whatToRenderName, component.WhatToRender); + builder.AddComponentParameter(5, testIdName, child); + builder.AddComponentParameter(6, logName, component.Log); builder.CloseComponent(); } @@ -5777,11 +5777,11 @@ public static void RenderNestedErrorBoundaries(RenderTreeBuilder builder, Render { // Create an error boundary builder.OpenComponent(0); - builder.AddAttribute(1, nameof(TestErrorBoundary.ChildContent), (RenderFragment)(builder => + builder.AddComponentParameter(1, nameof(TestErrorBoundary.ChildContent), (RenderFragment)(builder => { // ... containing another error boundary, containing the content builder.OpenComponent(0); - builder.AddAttribute(1, nameof(TestErrorBoundary.ChildContent), innerContent); + builder.AddComponentParameter(1, nameof(TestErrorBoundary.ChildContent), innerContent); builder.CloseComponent(); })); builder.CloseComponent(); diff --git a/src/Components/Web/src/Forms/EditForm.cs b/src/Components/Web/src/Forms/EditForm.cs index b2f3186daa3b..955b0ea9bc6f 100644 --- a/src/Components/Web/src/Forms/EditForm.cs +++ b/src/Components/Web/src/Forms/EditForm.cs @@ -123,9 +123,9 @@ protected override void BuildRenderTree(RenderTreeBuilder builder) builder.AddMultipleAttributes(1, AdditionalAttributes); builder.AddAttribute(2, "onsubmit", _handleSubmitDelegate); builder.OpenComponent>(3); - builder.AddAttribute(4, "IsFixed", true); - builder.AddAttribute(5, "Value", _editContext); - builder.AddAttribute(6, "ChildContent", ChildContent?.Invoke(_editContext)); + builder.AddComponentParameter(4, "IsFixed", true); + builder.AddComponentParameter(5, "Value", _editContext); + builder.AddComponentParameter(6, "ChildContent", ChildContent?.Invoke(_editContext)); builder.CloseComponent(); builder.CloseElement(); diff --git a/src/Components/Web/src/Forms/InputRadioGroup.cs b/src/Components/Web/src/Forms/InputRadioGroup.cs index 7e455fbd5cd8..f4ca4b94c733 100644 --- a/src/Components/Web/src/Forms/InputRadioGroup.cs +++ b/src/Components/Web/src/Forms/InputRadioGroup.cs @@ -57,8 +57,8 @@ protected override void BuildRenderTree(RenderTreeBuilder builder) // Note that we must not set IsFixed=true on the CascadingValue, because the mutations to _context // are what cause the descendant InputRadio components to re-render themselves builder.OpenComponent>(0); - builder.AddAttribute(2, "Value", _context); - builder.AddAttribute(3, "ChildContent", ChildContent); + builder.AddComponentParameter(2, "Value", _context); + builder.AddComponentParameter(3, "ChildContent", ChildContent); builder.CloseComponent(); } diff --git a/src/Components/Web/src/Head/HeadContent.cs b/src/Components/Web/src/Head/HeadContent.cs index ea954f82be0f..19aeb5bd94c0 100644 --- a/src/Components/Web/src/Head/HeadContent.cs +++ b/src/Components/Web/src/Head/HeadContent.cs @@ -21,8 +21,8 @@ public sealed class HeadContent : ComponentBase protected override void BuildRenderTree(RenderTreeBuilder builder) { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(SectionContent.Name), HeadOutlet.HeadSectionOutletName); - builder.AddAttribute(2, nameof(SectionContent.ChildContent), ChildContent); + builder.AddComponentParameter(1, nameof(SectionContent.Name), HeadOutlet.HeadSectionOutletName); + builder.AddComponentParameter(2, nameof(SectionContent.ChildContent), ChildContent); builder.CloseComponent(); } } diff --git a/src/Components/Web/src/Head/HeadOutlet.cs b/src/Components/Web/src/Head/HeadOutlet.cs index 472c3970bf94..8b29975f498e 100644 --- a/src/Components/Web/src/Head/HeadOutlet.cs +++ b/src/Components/Web/src/Head/HeadOutlet.cs @@ -37,22 +37,22 @@ protected override void BuildRenderTree(RenderTreeBuilder builder) { // Render the title content builder.OpenComponent(0); - builder.AddAttribute(1, nameof(SectionOutlet.Name), TitleSectionOutletName); + builder.AddComponentParameter(1, nameof(SectionOutlet.Name), TitleSectionOutletName); builder.CloseComponent(); // Render the default title if it exists if (!string.IsNullOrEmpty(_defaultTitle)) { builder.OpenComponent(2); - builder.AddAttribute(3, nameof(SectionContent.Name), TitleSectionOutletName); - builder.AddAttribute(4, nameof(SectionContent.IsDefaultContent), true); - builder.AddAttribute(5, nameof(SectionContent.ChildContent), (RenderFragment)BuildDefaultTitleRenderTree); + builder.AddComponentParameter(3, nameof(SectionContent.Name), TitleSectionOutletName); + builder.AddComponentParameter(4, nameof(SectionContent.IsDefaultContent), true); + builder.AddComponentParameter(5, nameof(SectionContent.ChildContent), (RenderFragment)BuildDefaultTitleRenderTree); builder.CloseComponent(); } // Render the rest of the head metadata builder.OpenComponent(6); - builder.AddAttribute(7, nameof(SectionOutlet.Name), HeadSectionOutletName); + builder.AddComponentParameter(7, nameof(SectionOutlet.Name), HeadSectionOutletName); builder.CloseComponent(); } diff --git a/src/Components/Web/src/Head/PageTitle.cs b/src/Components/Web/src/Head/PageTitle.cs index c295b324cb72..7a745973e5e7 100644 --- a/src/Components/Web/src/Head/PageTitle.cs +++ b/src/Components/Web/src/Head/PageTitle.cs @@ -21,8 +21,8 @@ public sealed class PageTitle : ComponentBase protected override void BuildRenderTree(RenderTreeBuilder builder) { builder.OpenComponent(0); - builder.AddAttribute(1, nameof(SectionContent.Name), HeadOutlet.TitleSectionOutletName); - builder.AddAttribute(2, nameof(SectionContent.ChildContent), (RenderFragment)BuildTitleRenderTree); + builder.AddComponentParameter(1, nameof(SectionContent.Name), HeadOutlet.TitleSectionOutletName); + builder.AddComponentParameter(2, nameof(SectionContent.ChildContent), (RenderFragment)BuildTitleRenderTree); builder.CloseComponent(); } diff --git a/src/Components/Web/test/Forms/EditFormTest.cs b/src/Components/Web/test/Forms/EditFormTest.cs index 6f1e58903841..aaa43822d995 100644 --- a/src/Components/Web/test/Forms/EditFormTest.cs +++ b/src/Components/Web/test/Forms/EditFormTest.cs @@ -107,8 +107,8 @@ class TestEditFormHostComponent : AutoRenderComponent protected override void BuildRenderTree(RenderTreeBuilder builder) { builder.OpenComponent(0); - builder.AddAttribute(1, "Model", Model); - builder.AddAttribute(2, "EditContext", EditContext); + builder.AddComponentParameter(1, "Model", Model); + builder.AddComponentParameter(2, "EditContext", EditContext); builder.CloseComponent(); } } diff --git a/src/Components/Web/test/Forms/InputRadioTest.cs b/src/Components/Web/test/Forms/InputRadioTest.cs index e25d729c0632..53438ceba14e 100644 --- a/src/Components/Web/test/Forms/InputRadioTest.cs +++ b/src/Components/Web/test/Forms/InputRadioTest.cs @@ -75,8 +75,8 @@ private static RenderFragment RadioButtonsWithoutGroup(string name) => (builder) foreach (var selectedValue in (TestEnum[])Enum.GetValues(typeof(TestEnum))) { builder.OpenComponent(0); - builder.AddAttribute(1, "Name", name); - builder.AddAttribute(2, "Value", selectedValue); + builder.AddComponentParameter(1, "Name", name); + builder.AddComponentParameter(2, "Value", selectedValue); builder.CloseComponent(); } }; @@ -84,14 +84,14 @@ private static RenderFragment RadioButtonsWithoutGroup(string name) => (builder) private static RenderFragment RadioButtonsWithGroup(string name, Expression> valueExpression) => (builder) => { builder.OpenComponent>(0); - builder.AddAttribute(1, "Name", name); - builder.AddAttribute(2, "ValueExpression", valueExpression); - builder.AddAttribute(2, "ChildContent", new RenderFragment((childBuilder) => + builder.AddComponentParameter(1, "Name", name); + builder.AddComponentParameter(2, "ValueExpression", valueExpression); + builder.AddComponentParameter(2, "ChildContent", new RenderFragment((childBuilder) => { foreach (var value in (TestEnum[])Enum.GetValues(typeof(TestEnum))) { childBuilder.OpenComponent(0); - childBuilder.AddAttribute(1, "Value", value); + childBuilder.AddComponentParameter(1, "Value", value); childBuilder.CloseComponent(); } })); @@ -139,8 +139,8 @@ private class TestInputRadioHostComponent : AutoRenderComponent protected override void BuildRenderTree(RenderTreeBuilder builder) { builder.OpenComponent>(0); - builder.AddAttribute(1, "Value", EditContext); - builder.AddAttribute(2, "ChildContent", InnerContent); + builder.AddComponentParameter(1, "Value", EditContext); + builder.AddComponentParameter(2, "ChildContent", InnerContent); builder.CloseComponent(); } } diff --git a/src/Components/Web/test/Forms/TestInputHostComponent.cs b/src/Components/Web/test/Forms/TestInputHostComponent.cs index d6f71756a0ba..f869c5eeee7e 100644 --- a/src/Components/Web/test/Forms/TestInputHostComponent.cs +++ b/src/Components/Web/test/Forms/TestInputHostComponent.cs @@ -22,14 +22,14 @@ internal class TestInputHostComponent : AutoRenderComponent protected override void BuildRenderTree(RenderTreeBuilder builder) { builder.OpenComponent>(0); - builder.AddAttribute(1, "Value", EditContext); - builder.AddAttribute(2, "ChildContent", new RenderFragment(childBuilder => + builder.AddComponentParameter(1, "Value", EditContext); + builder.AddComponentParameter(2, "ChildContent", new RenderFragment(childBuilder => { childBuilder.OpenComponent(0); - childBuilder.AddAttribute(0, "Value", Value); - childBuilder.AddAttribute(1, "ValueChanged", + childBuilder.AddComponentParameter(0, "Value", Value); + childBuilder.AddComponentParameter(1, "ValueChanged", EventCallback.Factory.Create(this, ValueChanged)); - childBuilder.AddAttribute(2, "ValueExpression", ValueExpression); + childBuilder.AddComponentParameter(2, "ValueExpression", ValueExpression); childBuilder.AddMultipleAttributes(3, AdditionalAttributes); childBuilder.CloseComponent(); })); diff --git a/src/Components/Web/test/Virtualization/VirtualizeTest.cs b/src/Components/Web/test/Virtualization/VirtualizeTest.cs index 511381dbf384..89819c4bf401 100644 --- a/src/Components/Web/test/Virtualization/VirtualizeTest.cs +++ b/src/Components/Web/test/Virtualization/VirtualizeTest.cs @@ -113,9 +113,9 @@ private RenderFragment BuildVirtualize( => builder => { builder.OpenComponent>(0); - builder.AddAttribute(1, "ItemSize", itemSize); - builder.AddAttribute(2, "ItemsProvider", itemsProvider); - builder.AddAttribute(3, "Items", items); + builder.AddComponentParameter(1, "ItemSize", itemSize); + builder.AddComponentParameter(2, "ItemsProvider", itemsProvider); + builder.AddComponentParameter(3, "Items", items); if (captureRenderedVirtualize != null) { From f6c249386ae37e95b7f7e690b7b11aa8714d13e6 Mon Sep 17 00:00:00 2001 From: Mackinnon Buck Date: Thu, 9 Feb 2023 13:37:11 -0800 Subject: [PATCH 3/4] Add/update RenderTreeBuilder tests --- .../test/Rendering/RenderTreeBuilderTest.cs | 194 ++++++++++++++++-- 1 file changed, 182 insertions(+), 12 deletions(-) diff --git a/src/Components/Components/test/Rendering/RenderTreeBuilderTest.cs b/src/Components/Components/test/Rendering/RenderTreeBuilderTest.cs index e314cef29c02..2f4ae8d3f734 100644 --- a/src/Components/Components/test/Rendering/RenderTreeBuilderTest.cs +++ b/src/Components/Components/test/Rendering/RenderTreeBuilderTest.cs @@ -438,6 +438,19 @@ public void CannotAddAttributeAtRoot() }); } + [Fact] + public void CannotAddComponentParameterAtRoot() + { + // Arrange + var builder = new RenderTreeBuilder(); + + // Act/Assert + Assert.Throws(() => + { + builder.AddComponentParameter(0, "name", "value"); + }); + } + [Fact] public void CannotAddDelegateAttributeAtRoot() { @@ -466,6 +479,21 @@ public void CannotAddAttributeToText() }); } + [Fact] + public void CannotAddComponentParameterToText() + { + // Arrange + var builder = new RenderTreeBuilder(); + + // Act/Assert + Assert.Throws(() => + { + builder.OpenElement(0, "some element"); + builder.AddContent(1, "hello"); + builder.AddComponentParameter(2, "name", "value"); + }); + } + [Fact] public void CannotAddEventHandlerAttributeToText() { @@ -495,6 +523,20 @@ public void CannotAddAttributeToRegion() }); } + [Fact] + public void CannotAddComponentParameterToRegion() + { + // Arrange + var builder = new RenderTreeBuilder(); + + // Act/Assert + Assert.Throws(() => + { + builder.OpenRegion(0); + builder.AddComponentParameter(1, "name", "value"); + }); + } + [Fact] public void CannotAddAttributeToElementReferenceCapture() { @@ -525,6 +567,35 @@ public void CannotAddAttributeToComponentReferenceCapture() }); } + [Fact] + public void CannotAddComponentParameterToComponentReferenceCapture() + { + // Arrange + var builder = new RenderTreeBuilder(); + + // Act/Assert + Assert.Throws(() => + { + builder.OpenComponent(0); + builder.AddComponentReferenceCapture(1, _ => { }); + builder.AddComponentParameter(2, "name", "value"); + }); + } + + [Fact] + public void CannotAddComponentParameterToElement() + { + // Arrange + var builder = new RenderTreeBuilder(); + + // Act/Assert + Assert.Throws(() => + { + builder.OpenElement(0, "some element"); + builder.AddComponentParameter(2, "name", "value"); + }); + } + [Fact] public void CanAddChildComponentsUsingGenericParam() { @@ -532,15 +603,15 @@ public void CanAddChildComponentsUsingGenericParam() var builder = new RenderTreeBuilder(); // Act - builder.OpenElement(10, "parent"); // 0: - builder.OpenComponent(11); // 1: - builder.CloseComponent(); // - builder.OpenComponent(14); // 4: - builder.CloseComponent(); // - builder.CloseElement(); // + builder.OpenElement(10, "parent"); // 0: + builder.OpenComponent(11); // 1: + builder.CloseComponent(); // + builder.OpenComponent(14); // 4: + builder.CloseComponent(); // + builder.CloseElement(); // // Assert Assert.Collection(builder.GetFrames().AsEnumerable(), @@ -733,7 +804,7 @@ public void CanAddComponentReferenceCaptureInsideComponent() // Act builder.OpenComponent(0); // 0: + builder.AddComponentParameter(1, "attribute2", 123); // 1: attribute2=intExpression123> builder.AddComponentReferenceCapture(2, myAction); // 2: # capture: myAction builder.AddContent(3, "some text"); // 3: some text builder.CloseComponent(); // @@ -885,6 +956,26 @@ public void AddAttribute_Component_Bool_SetsAttributeValue(bool value) frame => AssertFrame.Attribute(frame, "attr", value, 1)); } + [Theory] + [InlineData(false)] + [InlineData(true)] + public void AddComponentParameter_Component_Bool_SetsAttributeValue(bool value) + { + // Arrange + var builder = new RenderTreeBuilder(); + + // Act + builder.OpenComponent(0); + builder.AddComponentParameter(1, "attr", value); + builder.CloseComponent(); + + // Assert + Assert.Collection( + builder.GetFrames().AsEnumerable(), + frame => AssertFrame.Component(frame, 2, 0), + frame => AssertFrame.Attribute(frame, "attr", value, 1)); + } + [Fact] public void AddAttribute_Element_StringValue_AddsFrame() { @@ -940,6 +1031,26 @@ public void AddAttribute_Component_StringValue_SetsAttributeValue(string value) frame => AssertFrame.Attribute(frame, "attr", value, 1)); } + [Theory] + [InlineData("hi")] + [InlineData(null)] + public void AddComponentParameter_Component_StringValue_SetsAttributeValue(string value) + { + // Arrange + var builder = new RenderTreeBuilder(); + + // Act + builder.OpenComponent(0); + builder.AddComponentParameter(1, "attr", value); + builder.CloseComponent(); + + // Assert + Assert.Collection( + builder.GetFrames().AsEnumerable(), + frame => AssertFrame.Component(frame, 2, 0), + frame => AssertFrame.Attribute(frame, "attr", value, 1)); + } + [Fact] public void AddAttribute_Element_EventHandler_AddsFrame() { @@ -1039,6 +1150,25 @@ public void AddAttribute_Component_EventHandlerValue_SetsAttributeValue(Action AssertFrame.Attribute(frame, "attr", value, 1)); } + [Theory] + [MemberData(nameof(EventHandlerValues))] + public void AddComponentParameter_Component_EventHandlerValue_SetsAttributeValue(Action value) + { + // Arrange + var builder = new RenderTreeBuilder(); + + // Act + builder.OpenComponent(0); + builder.AddComponentParameter(1, "attr", value); + builder.CloseComponent(); + + // Assert + Assert.Collection( + builder.GetFrames().AsEnumerable(), + frame => AssertFrame.Component(frame, 2, 0), + frame => AssertFrame.Attribute(frame, "attr", value, 1)); + } + [Fact] public void AddAttribute_Element_EventCallback_AddsFrame() { @@ -1116,6 +1246,26 @@ public void AddAttribute_Component_EventCallback_AddsFrame() frame => AssertFrame.Attribute(frame, "attr", callback, 1)); } + [Fact] + public void AddComponentParameter_Component_EventCallback_AddsFrame() + { + // Arrange + var builder = new RenderTreeBuilder(); + var receiver = Mock.Of(); + var callback = new EventCallback(receiver, new Action(() => { })); + + // Act + builder.OpenComponent(0); + builder.AddComponentParameter(1, "attr", callback); + builder.CloseComponent(); + + // Assert + Assert.Collection( + builder.GetFrames().AsEnumerable(), + frame => AssertFrame.Component(frame, 2, 0), + frame => AssertFrame.Attribute(frame, "attr", callback, 1)); + } + [Fact] public void AddAttribute_Element_EventCallbackOfT_AddsFrame() { @@ -1193,6 +1343,26 @@ public void AddAttribute_Component_EventCallbackOfT_AddsFrame() frame => AssertFrame.Attribute(frame, "attr", callback, 1)); } + [Fact] + public void AddComponentParameter_Component_EventCallbackOfT_AddsFrame() + { + // Arrange + var builder = new RenderTreeBuilder(); + var receiver = Mock.Of(); + var callback = new EventCallback(receiver, new Action((s) => { })); + + // Act + builder.OpenComponent(0); + builder.AddComponentParameter(1, "attr", callback); + builder.CloseComponent(); + + // Assert + Assert.Collection( + builder.GetFrames().AsEnumerable(), + frame => AssertFrame.Component(frame, 2, 0), + frame => AssertFrame.Attribute(frame, "attr", callback, 1)); + } + [Fact] public void AddAttribute_Element_ObjectBoolTrue_AddsFrame() { @@ -1550,9 +1720,9 @@ public void CanAddKeyToComponent() // Act builder.OpenComponent(0); - builder.AddAttribute(1, "param before", 123); + builder.AddComponentParameter(1, "param before", 123); builder.SetKey(keyValue); - builder.AddAttribute(2, "param after", 456); + builder.AddComponentParameter(2, "param after", 456); builder.CloseComponent(); // Assert From 1a393a24332529c5ee041584603d1c0822df28b0 Mon Sep 17 00:00:00 2001 From: Mackinnon Buck Date: Thu, 9 Feb 2023 14:49:27 -0800 Subject: [PATCH 4/4] Remove bool overload, add new test --- .../Components/src/PublicAPI.Unshipped.txt | 3 +- .../src/Rendering/RenderTreeBuilder.cs | 12 ---- .../Components/test/RendererTest.cs | 59 +++++++++++++++++++ 3 files changed, 60 insertions(+), 14 deletions(-) diff --git a/src/Components/Components/src/PublicAPI.Unshipped.txt b/src/Components/Components/src/PublicAPI.Unshipped.txt index ca1af7d2da0a..40ea919e8630 100644 --- a/src/Components/Components/src/PublicAPI.Unshipped.txt +++ b/src/Components/Components/src/PublicAPI.Unshipped.txt @@ -3,5 +3,4 @@ Microsoft.AspNetCore.Components.ComponentBase.DispatchExceptionAsync(System.Exce Microsoft.AspNetCore.Components.RenderHandle.DispatchExceptionAsync(System.Exception! exception) -> System.Threading.Tasks.Task! *REMOVED*Microsoft.AspNetCore.Components.NavigationManager.ToAbsoluteUri(string! relativeUri) -> System.Uri! Microsoft.AspNetCore.Components.NavigationManager.ToAbsoluteUri(string? relativeUri) -> System.Uri! -Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder.AddComponentParameter(int sequence, string! name, bool value) -> void -Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder.AddComponentParameter(int sequence, string! name, object? value) -> void \ No newline at end of file +Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder.AddComponentParameter(int sequence, string! name, object? value) -> void diff --git a/src/Components/Components/src/Rendering/RenderTreeBuilder.cs b/src/Components/Components/src/Rendering/RenderTreeBuilder.cs index 7db3d8f7f6c7..ae97374c6c36 100644 --- a/src/Components/Components/src/Rendering/RenderTreeBuilder.cs +++ b/src/Components/Components/src/Rendering/RenderTreeBuilder.cs @@ -505,18 +505,6 @@ public void OpenComponent(int sequence, [DynamicallyAccessedMembers(Component)] OpenComponentUnchecked(sequence, componentType); } - /// - /// Appends a frame representing a component parameter. - /// - /// An integer that represents the position of the instruction in the source code. - /// The name of the attribute. - /// The value of the attribute. - public void AddComponentParameter(int sequence, string name, bool value) - { - AssertCanAddComponentParameter(); - _entries.AppendAttribute(sequence, name, value ? BoxedTrue : BoxedFalse); - } - /// /// Appends a frame representing a component parameter. /// diff --git a/src/Components/Components/test/RendererTest.cs b/src/Components/Components/test/RendererTest.cs index 5b4005798e39..8f4ac760dc68 100644 --- a/src/Components/Components/test/RendererTest.cs +++ b/src/Components/Components/test/RendererTest.cs @@ -4406,6 +4406,28 @@ public void CannotAccessParameterViewAfterSynchronousReturn() Assert.Equal($"The {nameof(ParameterView)} instance can no longer be read because it has expired. {nameof(ParameterView)} can only be read synchronously and must not be stored for later use.", ex.Message); } + [Fact] + public async Task CanSetComponentParameter_WhenParameterTypeHasImplicitConversionToString() + { + // Arrange + var renderer = new TestRenderer(); + var parameterValue = new ImplicitlyConvertsToString("Hello"); + var rootComponent = new TestComponent(builder => + { + builder.OpenComponent(0); + builder.AddComponentParameter(1, nameof(ImplicitConversionComponent.SomeParam), parameterValue); + builder.CloseComponent(); + }); + + // Act + var rootComponentId = renderer.AssignRootComponentId(rootComponent); + await renderer.RenderRootComponentAsync(rootComponentId); + var capturingComponent = (ImplicitConversionComponent)renderer.GetCurrentRenderTreeFrames(rootComponentId).Array[0].Component; + + // Assert + Assert.Same(parameterValue, capturingComponent.SomeParam); + } + [Fact] public void CanUseCustomComponentActivatorFromConstructorParameter() { @@ -5854,4 +5876,41 @@ protected override void BuildRenderTree(RenderTreeBuilder builder) RenderCount++; } } + + private sealed class ImplicitConversionComponent : IComponent + { + [Parameter] + public ImplicitlyConvertsToString SomeParam { get; set; } + + public void Attach(RenderHandle renderHandle) + { + } + + public Task SetParametersAsync(ParameterView parameters) + { + foreach (var parameter in parameters) + { + if (parameter.Name.Equals(nameof(SomeParam), StringComparison.OrdinalIgnoreCase)) + { + // 'SomeParam' will be assigned to null if an implicit conversion changed the + // parameter type. + SomeParam = parameter.Value as ImplicitlyConvertsToString; + } + } + + return Task.CompletedTask; + } + } + + private sealed class ImplicitlyConvertsToString + { + private readonly string _value; + + public ImplicitlyConvertsToString(string value) + { + _value = value; + } + + public static implicit operator string(ImplicitlyConvertsToString value) => value._value; + } }