From 7cd5228b7f1dce0c194d0260150581ff2cd4cc94 Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Tue, 16 Jan 2018 16:58:47 +0000 Subject: [PATCH] In RazorCompiler, support attributes whose values are C# code blocks (treated as event handlers) --- .../Engine/BlazorIntermediateNodeWriter.cs | 12 ++++- .../RazorCompilerTest.cs | 45 ++++++++++++++++--- .../BasicTestApp/CounterComponent.cshtml | 7 +-- 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.Blazor.Build/Core/RazorCompilation/Engine/BlazorIntermediateNodeWriter.cs b/src/Microsoft.Blazor.Build/Core/RazorCompilation/Engine/BlazorIntermediateNodeWriter.cs index 5d951af204..4ec8c01221 100644 --- a/src/Microsoft.Blazor.Build/Core/RazorCompilation/Engine/BlazorIntermediateNodeWriter.cs +++ b/src/Microsoft.Blazor.Build/Core/RazorCompilation/Engine/BlazorIntermediateNodeWriter.cs @@ -76,7 +76,17 @@ namespace Microsoft.Blazor.Build.Core.RazorCompilation.Engine public override void WriteCSharpCodeAttributeValue(CodeRenderingContext context, CSharpCodeAttributeValueIntermediateNode node) { - throw new System.NotImplementedException(nameof(WriteCSharpCodeAttributeValue)); + if (_currentAttributeValues == null) + { + throw new InvalidOperationException($"Invoked {nameof(WriteCSharpCodeAttributeValue)} while {nameof(_currentAttributeValues)} was null."); + } + + // For attributes like "onsomeevent=@{ /* some C# code */ }", we treat it as if you + // wrote "onsomeevent=@(_ => { /* some C# code */ })" because then it works as an + // event handler and is a reasonable syntax for that. + var innerCSharp = (IntermediateToken)node.Children.Single(); + innerCSharp.Content = $"_ => {{ {innerCSharp.Content} }}"; + _currentAttributeValues.Add(innerCSharp); } public override void WriteCSharpExpression(CodeRenderingContext context, CSharpExpressionIntermediateNode node) diff --git a/test/Microsoft.Blazor.Build.Test/RazorCompilerTest.cs b/test/Microsoft.Blazor.Build.Test/RazorCompilerTest.cs index ec4113e53a..7f74718fae 100644 --- a/test/Microsoft.Blazor.Build.Test/RazorCompilerTest.cs +++ b/test/Microsoft.Blazor.Build.Test/RazorCompilerTest.cs @@ -236,18 +236,53 @@ namespace Microsoft.Blazor.Build.Test { // Arrange/Act var component = CompileToComponent( - "" - + @"@functions { - void MyHandleEvent(Microsoft.Blazor.RenderTree.UIEventArgs eventArgs) {} - }"); + @" + @functions { + public bool HandlerWasCalled { get; set; } = false; + + void MyHandleEvent(Microsoft.Blazor.RenderTree.UIEventArgs eventArgs) + { + HandlerWasCalled = true; + } + }"); + var handlerWasCalledProperty = component.GetType().GetProperty("HandlerWasCalled"); // Assert - Assert.Collection(GetRenderTree(component), + Assert.False((bool)handlerWasCalledProperty.GetValue(component)); + Assert.Collection(GetRenderTree(component).Where(NotWhitespace), node => AssertNode.Element(node, "elem", 1), node => { Assert.Equal(RenderTreeNodeType.Attribute, node.NodeType); Assert.NotNull(node.AttributeEventHandlerValue); + + node.AttributeEventHandlerValue(null); + Assert.True((bool)handlerWasCalledProperty.GetValue(component)); + }); + } + + [Fact] + public void SupportsAttributesWithCSharpCodeBlockValues() + { + // Arrange/Act + var component = CompileToComponent( + @" + @functions { + public bool DidInvokeCode { get; set; } = false; + }"); + var didInvokeCodeProperty = component.GetType().GetProperty("DidInvokeCode"); + + // Assert + Assert.False((bool)didInvokeCodeProperty.GetValue(component)); + Assert.Collection(GetRenderTree(component).Where(NotWhitespace), + node => AssertNode.Element(node, "elem", 1), + node => + { + Assert.Equal(RenderTreeNodeType.Attribute, node.NodeType); + Assert.NotNull(node.AttributeEventHandlerValue); + + node.AttributeEventHandlerValue(null); + Assert.True((bool)didInvokeCodeProperty.GetValue(component)); }); } diff --git a/test/testapps/BasicTestApp/CounterComponent.cshtml b/test/testapps/BasicTestApp/CounterComponent.cshtml index 194eb1419b..33802c3555 100644 --- a/test/testapps/BasicTestApp/CounterComponent.cshtml +++ b/test/testapps/BasicTestApp/CounterComponent.cshtml @@ -1,12 +1,7 @@ 

Counter

Current count: @currentCount

- + @functions { int currentCount = 0; - - void OnButtonClicked(Microsoft.Blazor.RenderTree.UIEventArgs eventArgs) - { - currentCount++; - } }