From 1b4fa4781ab4f6727486a7179204365506acaa1e Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Fri, 26 Jan 2018 09:40:48 -0800 Subject: [PATCH] Give attribute nodes a single object-valued value so they can be used for component properties too. --- .../src/Rendering/RenderTreeNode.ts | 7 +++---- .../RenderTree/RenderTreeDiffComputer.cs | 9 +++++---- .../RenderTree/RenderTreeNode.cs | 10 ++-------- .../Rendering/ComponentState.cs | 4 ++-- .../RazorCompilerTest.cs | 12 ++++++------ .../Microsoft.AspNetCore.Blazor.Test/RendererTest.cs | 4 ++-- test/shared/AssertNode.cs | 2 +- 7 files changed, 21 insertions(+), 27 deletions(-) diff --git a/src/Microsoft.AspNetCore.Blazor.Browser.JS/src/Rendering/RenderTreeNode.ts b/src/Microsoft.AspNetCore.Blazor.Browser.JS/src/Rendering/RenderTreeNode.ts index 8078d31835..a710373eb5 100644 --- a/src/Microsoft.AspNetCore.Blazor.Browser.JS/src/Rendering/RenderTreeNode.ts +++ b/src/Microsoft.AspNetCore.Blazor.Browser.JS/src/Rendering/RenderTreeNode.ts @@ -1,6 +1,6 @@ import { System_String, System_Array, Pointer } from '../Platform/Platform'; import { platform } from '../Environment'; -const renderTreeNodeStructLength = 44; +const renderTreeNodeStructLength = 40; // To minimise GC pressure, instead of instantiating a JS object to represent each tree node, // we work in terms of pointers to the structs on the .NET heap, and use static functions that @@ -18,9 +18,8 @@ export const renderTreeNode = { textContent: (node: RenderTreeNodePointer) => platform.readStringField(node, 16), attributeName: (node: RenderTreeNodePointer) => platform.readStringField(node, 20), attributeValue: (node: RenderTreeNodePointer) => platform.readStringField(node, 24), - attributeEventHandlerValue: (node: RenderTreeNodePointer) => platform.readObjectField(node, 28), - componentId: (node: RenderTreeNodePointer) => platform.readInt32Field(node, 36), - component: (node: RenderTreeNodePointer) => platform.readObjectField(node, 40), + componentId: (node: RenderTreeNodePointer) => platform.readInt32Field(node, 32), + component: (node: RenderTreeNodePointer) => platform.readObjectField(node, 36), }; export enum NodeType { diff --git a/src/Microsoft.AspNetCore.Blazor/RenderTree/RenderTreeDiffComputer.cs b/src/Microsoft.AspNetCore.Blazor/RenderTree/RenderTreeDiffComputer.cs index 90f7ee6424..963a436b96 100644 --- a/src/Microsoft.AspNetCore.Blazor/RenderTree/RenderTreeDiffComputer.cs +++ b/src/Microsoft.AspNetCore.Blazor/RenderTree/RenderTreeDiffComputer.cs @@ -271,10 +271,11 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree var newName = newTree[newNodeIndex].AttributeName; if (string.Equals(oldName, newName, StringComparison.Ordinal)) { - var changed = - !string.Equals(oldTree[oldNodeIndex].AttributeValue, newTree[newNodeIndex].AttributeValue, StringComparison.Ordinal) - || oldTree[oldNodeIndex].AttributeEventHandlerValue != newTree[newNodeIndex].AttributeEventHandlerValue; - if (changed) + // Using Equals to account for string comparisons, nulls, etc. + var valueChanged = !Equals( + oldTree[oldNodeIndex].AttributeValue, + newTree[newNodeIndex].AttributeValue); + if (valueChanged) { Append(RenderTreeEdit.SetAttribute(siblingIndex, newNodeIndex)); } diff --git a/src/Microsoft.AspNetCore.Blazor/RenderTree/RenderTreeNode.cs b/src/Microsoft.AspNetCore.Blazor/RenderTree/RenderTreeNode.cs index afa42cd9fd..d6351209b9 100644 --- a/src/Microsoft.AspNetCore.Blazor/RenderTree/RenderTreeNode.cs +++ b/src/Microsoft.AspNetCore.Blazor/RenderTree/RenderTreeNode.cs @@ -56,13 +56,7 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree /// If the property equals , /// gets the attribute value. Otherwise, the value is . /// - public string AttributeValue { get; private set; } - - /// - /// If the property equals , - /// gets the attribute's event handle, if any. Otherwise, the value is . - /// - public UIEventHandler AttributeEventHandlerValue { get; private set; } + public object AttributeValue { get; private set; } /// /// If the property equals , @@ -109,7 +103,7 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree Sequence = sequence, NodeType = RenderTreeNodeType.Attribute, AttributeName = name, - AttributeEventHandlerValue = value + AttributeValue = value }; internal static RenderTreeNode ChildComponent(int sequence) where T: IComponent => new RenderTreeNode diff --git a/src/Microsoft.AspNetCore.Blazor/Rendering/ComponentState.cs b/src/Microsoft.AspNetCore.Blazor/Rendering/ComponentState.cs index 6473535727..6d38a6ea95 100644 --- a/src/Microsoft.AspNetCore.Blazor/Rendering/ComponentState.cs +++ b/src/Microsoft.AspNetCore.Blazor/Rendering/ComponentState.cs @@ -67,10 +67,10 @@ namespace Microsoft.AspNetCore.Blazor.Rendering } var nodes = _renderTreeBuilderCurrent.GetNodes(); - var eventHandler = nodes.Array[renderTreeIndex].AttributeEventHandlerValue; + var eventHandler = nodes.Array[renderTreeIndex].AttributeValue as UIEventHandler; if (eventHandler == null) { - throw new ArgumentException($"The render tree node at index {renderTreeIndex} has a null value for {nameof(RenderTreeNode.AttributeEventHandlerValue)}."); + throw new ArgumentException($"The render tree node at index {renderTreeIndex} does not specify a {nameof(UIEventHandler)}."); } eventHandler.Invoke(eventArgs); diff --git a/test/Microsoft.AspNetCore.Blazor.Build.Test/RazorCompilerTest.cs b/test/Microsoft.AspNetCore.Blazor.Build.Test/RazorCompilerTest.cs index cc1ce0a06a..1c4400d9a9 100644 --- a/test/Microsoft.AspNetCore.Blazor.Build.Test/RazorCompilerTest.cs +++ b/test/Microsoft.AspNetCore.Blazor.Build.Test/RazorCompilerTest.cs @@ -254,9 +254,9 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test node => { Assert.Equal(RenderTreeNodeType.Attribute, node.NodeType); - Assert.NotNull(node.AttributeEventHandlerValue); + Assert.NotNull(node.AttributeValue); - node.AttributeEventHandlerValue(null); + ((UIEventHandler)node.AttributeValue)(null); Assert.True((bool)handlerWasCalledProperty.GetValue(component)); }); } @@ -279,9 +279,9 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test node => { Assert.Equal(RenderTreeNodeType.Attribute, node.NodeType); - Assert.NotNull(node.AttributeEventHandlerValue); + Assert.NotNull(node.AttributeValue); - node.AttributeEventHandlerValue(null); + ((UIEventHandler)node.AttributeValue)(null); Assert.True((bool)didInvokeCodeProperty.GetValue(component)); }); } @@ -325,9 +325,9 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test node => { Assert.Equal(RenderTreeNodeType.Attribute, node.NodeType); - Assert.NotNull(node.AttributeEventHandlerValue); + Assert.NotNull(node.AttributeValue); - node.AttributeEventHandlerValue(null); + ((UIEventHandler)node.AttributeValue)(null); Assert.True((bool)didInvokeCodeProperty.GetValue(component)); }); } diff --git a/test/Microsoft.AspNetCore.Blazor.Test/RendererTest.cs b/test/Microsoft.AspNetCore.Blazor.Test/RendererTest.cs index 5f87243b2f..738348d426 100644 --- a/test/Microsoft.AspNetCore.Blazor.Test/RendererTest.cs +++ b/test/Microsoft.AspNetCore.Blazor.Test/RendererTest.cs @@ -134,7 +134,7 @@ namespace Microsoft.AspNetCore.Blazor.Test var (eventHandlerNodeIndex, _) = FirstWithIndex( renderer.RenderTreesByComponentId[componentId], - node => node.AttributeEventHandlerValue != null); + node => node.AttributeValue != null); // Assert: Event not yet fired Assert.Null(receivedArgs); @@ -171,7 +171,7 @@ namespace Microsoft.AspNetCore.Blazor.Test // Find nested component's event handler ndoe var (eventHandlerNodeIndex, _) = FirstWithIndex( renderer.RenderTreesByComponentId[nestedComponentId], - node => node.AttributeEventHandlerValue != null); + node => node.AttributeValue != null); // Assert: Event not yet fired Assert.Null(receivedArgs); diff --git a/test/shared/AssertNode.cs b/test/shared/AssertNode.cs index 355389a9fd..b8a39e6fc4 100644 --- a/test/shared/AssertNode.cs +++ b/test/shared/AssertNode.cs @@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Blazor.Test.Shared public static void Attribute(RenderTreeNode node, string attributeName, UIEventHandler attributeEventHandlerValue) { AssertNode.Attribute(node, attributeName); - Assert.Equal(attributeEventHandlerValue, node.AttributeEventHandlerValue); + Assert.Equal(attributeEventHandlerValue, node.AttributeValue); } public static void Component(RenderTreeNode node) where T : IComponent