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