Add support for Action event handlers

This change adds `Action` to the set of types that have an overload on
RenderTreeBuilder. Additionally, we special case `Action` in the runtime
because passing the event args via DynamicInvoke() would throw.

Finally, reverted some of the clutter introduced by the first pass of
the event handler feature.
This commit is contained in:
Ryan Nowak 2018-04-10 22:34:06 -07:00
parent 6d3838ef9d
commit 8485e2ea10
28 changed files with 518 additions and 40 deletions

View File

@ -1,5 +1,4 @@
@page "/counter"
@using Microsoft.AspNetCore.Blazor
<h1>Counter</h1>
@ -10,7 +9,7 @@
@functions {
int currentCount = 0;
void IncrementCount(UIMouseEventArgs e)
void IncrementCount()
{
currentCount++;
}

View File

@ -32,6 +32,15 @@ namespace Microsoft.AspNetCore.Blazor.Components
return value;
}
/// <summary>
/// Not intended to be used directly.
/// </summary>
public static MulticastDelegate GetEventHandlerValue<T>(Action value)
where T : UIEventArgs
{
return value;
}
/// <summary>
/// Not intended to be used directly.
/// </summary>

View File

@ -148,6 +148,24 @@ namespace Microsoft.AspNetCore.Blazor.RenderTree
}
}
/// <summary>
/// <para>
/// Appends a frame representing an <see cref="Action"/>-valued attribute.
/// </para>
/// <para>
/// The attribute is associated with the most recently added element. If the value is <c>null</c> and the
/// current element is not a component, the frame will be omitted.
/// </para>
/// </summary>
/// <param name="builder">The <see cref="RenderTreeBuilder"/>.</param>
/// <param name="sequence">An integer that represents the position of the instruction in the source code.</param>
/// <param name="name">The name of the attribute.</param>
/// <param name="value">The value of the attribute.</param>
public void AddAttribute(int sequence, string name, Action value)
{
AddAttribute(sequence, name, (MulticastDelegate)value);
}
/// <summary>
/// <para>
/// Appends a frame representing an <see cref="UIEventHandler"/>-valued attribute.

View File

@ -125,15 +125,20 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
{
_eventHandlersById.Add(id, wrapper);
}
// IMPORTANT: we're creating an additional delegate when necessary. This is
// going to get cached in _eventHandlersById, but the render tree diff
// will operate on 'AttributeValue' which means that we'll only create a new
// wrapper delegate when the underlying delegate changes.
//
// TLDR: If the component uses a method group or a non-capturing lambda
// we don't allocate much.
else if (frame.AttributeValue is Action action)
{
_eventHandlersById.Add(id, (UIEventArgs e) => action());
}
else if (frame.AttributeValue is MulticastDelegate @delegate)
{
// IMPORTANT: we're creating an additional delegate when necessary. This is
// going to get cached in _eventHandlersById, but the render tree diff
// will operate on 'AttributeValue' which means that we'll only create a new
// wrapper delegate when the underlying delegate changes.
//
// TLDR: If the component uses a method group or a non-capturing lambda
// we don't allocate much.
_eventHandlersById.Add(id, (UIEventArgs e) => @delegate.DynamicInvoke(e));
}

View File

@ -3,7 +3,6 @@
using Microsoft.CodeAnalysis.CSharp;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.AspNetCore.Blazor.Build.Test
{
@ -276,7 +275,23 @@ namespace Test
}
[Fact]
public void EventHandler_OnElement_WithLambdaDelegate()
public void EventHandler_OnElement_WithNoArgsLambdaDelegate()
{
// Arrange
// Act
var generated = CompileToCSharp(@"
@using Microsoft.AspNetCore.Blazor
<input onclick=""@(() => { })"" />");
// Assert
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
CompileToAssembly(generated);
}
[Fact]
public void EventHandler_OnElement_WithEventArgsLambdaDelegate()
{
// Arrange
@ -292,7 +307,27 @@ namespace Test
}
[Fact]
public void EventHandler_OnElement_WithDelegate()
public void EventHandler_OnElement_WithNoArgMethodGroup()
{
// Arrange
// Act
var generated = CompileToCSharp(@"
@using Microsoft.AspNetCore.Blazor
<input onclick=""@OnClick"" />
@functions {
void OnClick() {
}
}");
// Assert
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
CompileToAssembly(generated);
}
[Fact]
public void EventHandler_OnElement_WithEventArgsMethodGroup()
{
// Arrange
@ -310,5 +345,25 @@ namespace Test
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
CompileToAssembly(generated);
}
[Fact]
public void EventHandler_OnElement_ArbitraryEventName_WithEventArgsMethodGroup()
{
// Arrange
// Act
var generated = CompileToCSharp(@"
@using Microsoft.AspNetCore.Blazor
<input onclick=""@OnClick"" />
@functions {
void OnClick(UIEventArgs e) {
}
}");
// Assert
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
CompileToAssembly(generated);
}
}
}

View File

@ -0,0 +1,32 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Blazor;
public class TestComponent : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
{
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
builder.OpenElement(0, "input");
builder.AddAttribute(1, "onclick", Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(OnClick));
builder.CloseElement();
builder.AddContent(2, "\n");
}
#pragma warning restore 1998
#line 3 "x:\dir\subdir\Test\TestComponent.cshtml"
void OnClick(UIEventArgs e) {
}
#line default
#line hidden
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,24 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [14] ) - System
UsingDirective - (18:2,1 [34] ) - System.Collections.Generic
UsingDirective - (53:3,1 [19] ) - System.Linq
UsingDirective - (73:4,1 [30] ) - System.Threading.Tasks
UsingDirective - (1:0,1 [35] x:\dir\subdir\Test\TestComponent.cshtml) - Microsoft.AspNetCore.Blazor
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Blazor.Components.BlazorComponent -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (53:1,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlContent - (64:1,28 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (64:1,28 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (78:2,12 [44] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (78:2,12 [44] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n void OnClick(UIEventArgs e) {\n }\n

View File

@ -0,0 +1,11 @@
Source Location: (78:2,12 [44] x:\dir\subdir\Test\TestComponent.cshtml)
|
void OnClick(UIEventArgs e) {
}
|
Generated Location: (964:23,12 [44] )
|
void OnClick(UIEventArgs e) {
}
|

View File

@ -0,0 +1,24 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Blazor;
public class TestComponent : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
{
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
builder.OpenElement(0, "input");
builder.AddAttribute(1, "onclick", Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(x => { }));
builder.CloseElement();
}
#pragma warning restore 1998
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,20 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [14] ) - System
UsingDirective - (18:2,1 [34] ) - System.Collections.Generic
UsingDirective - (53:3,1 [19] ) - System.Linq
UsingDirective - (73:4,1 [30] ) - System.Threading.Tasks
UsingDirective - (1:0,1 [35] x:\dir\subdir\Test\TestComponent.cshtml) - Microsoft.AspNetCore.Blazor
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Blazor.Components.BlazorComponent -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (54:1,18 [8] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - x => { }
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />

View File

@ -0,0 +1,32 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Blazor;
public class TestComponent : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
{
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
builder.OpenElement(0, "input");
builder.AddAttribute(1, "onclick", Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(OnClick));
builder.CloseElement();
builder.AddContent(2, "\n");
}
#pragma warning restore 1998
#line 3 "x:\dir\subdir\Test\TestComponent.cshtml"
void OnClick(UIMouseEventArgs e) {
}
#line default
#line hidden
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,24 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [14] ) - System
UsingDirective - (18:2,1 [34] ) - System.Collections.Generic
UsingDirective - (53:3,1 [19] ) - System.Linq
UsingDirective - (73:4,1 [30] ) - System.Threading.Tasks
UsingDirective - (1:0,1 [35] x:\dir\subdir\Test\TestComponent.cshtml) - Microsoft.AspNetCore.Blazor
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Blazor.Components.BlazorComponent -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (53:1,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlContent - (64:1,28 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (64:1,28 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (78:2,12 [49] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (78:2,12 [49] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n void OnClick(UIMouseEventArgs e) {\n }\n

View File

@ -0,0 +1,11 @@
Source Location: (78:2,12 [49] x:\dir\subdir\Test\TestComponent.cshtml)
|
void OnClick(UIMouseEventArgs e) {
}
|
Generated Location: (964:23,12 [49] )
|
void OnClick(UIMouseEventArgs e) {
}
|

View File

@ -0,0 +1,32 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Blazor;
public class TestComponent : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
{
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
builder.OpenElement(0, "input");
builder.AddAttribute(1, "onclick", Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(OnClick));
builder.CloseElement();
builder.AddContent(2, "\n");
}
#pragma warning restore 1998
#line 3 "x:\dir\subdir\Test\TestComponent.cshtml"
void OnClick() {
}
#line default
#line hidden
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,24 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [14] ) - System
UsingDirective - (18:2,1 [34] ) - System.Collections.Generic
UsingDirective - (53:3,1 [19] ) - System.Linq
UsingDirective - (73:4,1 [30] ) - System.Threading.Tasks
UsingDirective - (1:0,1 [35] x:\dir\subdir\Test\TestComponent.cshtml) - Microsoft.AspNetCore.Blazor
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Blazor.Components.BlazorComponent -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (53:1,17 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - OnClick
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />
HtmlContent - (64:1,28 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (64:1,28 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (78:2,12 [31] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (78:2,12 [31] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n void OnClick() {\n }\n

View File

@ -0,0 +1,11 @@
Source Location: (78:2,12 [31] x:\dir\subdir\Test\TestComponent.cshtml)
|
void OnClick() {
}
|
Generated Location: (964:23,12 [31] )
|
void OnClick() {
}
|

View File

@ -0,0 +1,24 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Blazor;
public class TestComponent : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
{
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
builder.OpenElement(0, "input");
builder.AddAttribute(1, "onclick", Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(() => { }));
builder.CloseElement();
}
#pragma warning restore 1998
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,20 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [14] ) - System
UsingDirective - (18:2,1 [34] ) - System.Collections.Generic
UsingDirective - (53:3,1 [19] ) - System.Linq
UsingDirective - (73:4,1 [30] ) - System.Threading.Tasks
UsingDirective - (1:0,1 [35] x:\dir\subdir\Test\TestComponent.cshtml) - Microsoft.AspNetCore.Blazor
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Blazor.Components.BlazorComponent -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent -
IntermediateToken - - Html - <input
HtmlAttribute - - =" - "
CSharpExpressionAttributeValue - -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetEventHandlerValue<Microsoft.AspNetCore.Blazor.UIMouseEventArgs>(
IntermediateToken - (54:1,18 [9] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - () => { }
IntermediateToken - - CSharp - )
HtmlContent -
IntermediateToken - - Html - />

View File

@ -498,7 +498,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
}
[Fact]
public void AddAttribute_Element_EventHandler_AddsFrame()
public void AddAttribute_Element_UIEventHandler_AddsFrame()
{
// Arrange
var builder = new RenderTreeBuilder(new TestRenderer());
@ -518,7 +518,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
}
[Fact]
public void AddAttribute_Element_NullEventHandler_IgnoresFrame()
public void AddAttribute_Element_NullUIEventHandler_IgnoresFrame()
{
// Arrange
var builder = new RenderTreeBuilder(new TestRenderer());
@ -534,6 +534,43 @@ namespace Microsoft.AspNetCore.Blazor.Test
frame => AssertFrame.Element(frame, "elem", 1, 0));
}
[Fact]
public void AddAttribute_Element_Action_AddsFrame()
{
// Arrange
var builder = new RenderTreeBuilder(new TestRenderer());
var value = new Action(() => { });
// Act
builder.OpenElement(0, "elem");
builder.AddAttribute(1, "attr", value);
builder.CloseElement();
// Assert
Assert.Collection(
builder.GetFrames(),
frame => AssertFrame.Element(frame, "elem", 2, 0),
frame => AssertFrame.Attribute(frame, "attr", value, 1));
}
[Fact]
public void AddAttribute_Element_NullAction_IgnoresFrame()
{
// Arrange
var builder = new RenderTreeBuilder(new TestRenderer());
// Act
builder.OpenElement(0, "elem");
builder.AddAttribute(1, "attr", (Action)null);
builder.CloseElement();
// Assert
Assert.Collection(
builder.GetFrames(),
frame => AssertFrame.Element(frame, "elem", 1, 0));
}
public static TheoryData<UIEventHandler> UIEventHandlerValues => new TheoryData<UIEventHandler>
{
null,
@ -651,7 +688,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
}
[Fact]
public void AddAttribute_Element_ObjectEventHandler_AddsFrame()
public void AddAttribute_Element_ObjectUIEventHandler_AddsFrame()
{
// Arrange
var builder = new RenderTreeBuilder(new TestRenderer());
@ -671,7 +708,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
}
[Fact]
public void AddAttribute_Component_ObjectEventHandleValue_SetsAttributeValue()
public void AddAttribute_Component_ObjectUIEventHandleValue_SetsAttributeValue()
{
// Arrange
var builder = new RenderTreeBuilder(new TestRenderer());
@ -690,6 +727,46 @@ namespace Microsoft.AspNetCore.Blazor.Test
frame => AssertFrame.Attribute(frame, "attr", value, 1));
}
[Fact]
public void AddAttribute_Element_ObjectAction_AddsFrame()
{
// Arrange
var builder = new RenderTreeBuilder(new TestRenderer());
var value = new Action(() => { });
// Act
builder.OpenElement(0, "elem");
builder.AddAttribute(1, "attr", (object)value);
builder.CloseElement();
// Assert
Assert.Collection(
builder.GetFrames(),
frame => AssertFrame.Element(frame, "elem", 2, 0),
frame => AssertFrame.Attribute(frame, "attr", value, 1));
}
[Fact]
public void AddAttribute_Component_ObjectAction_SetsAttributeValue()
{
// Arrange
var builder = new RenderTreeBuilder(new TestRenderer());
var value = new Action(() => { });
// Act
builder.OpenComponent<TestComponent>(0);
builder.AddAttribute(1, "attr", (object)value);
builder.CloseComponent();
// Assert
Assert.Collection(
builder.GetFrames(),
frame => AssertFrame.Component<TestComponent>(frame, 2, 0),
frame => AssertFrame.Attribute(frame, "attr", value, 1));
}
[Fact]
public void AddAttribute_Element_ObjectNull_IgnoresFrame()
{

View File

@ -217,6 +217,34 @@ namespace Microsoft.AspNetCore.Blazor.Test
Assert.Same(eventArgs, receivedArgs);
}
[Fact]
public void CanDispatchActionEventsToTopLevelComponents()
{
// Arrange: Render a component with an event handler
var renderer = new TestRenderer();
object receivedArgs = null;
var component = new EventComponent
{
OnClickAction = () => { receivedArgs = new object(); }
};
var componentId = renderer.AssignComponentId(component);
component.TriggerRender();
var eventHandlerId = renderer.Batches.Single()
.ReferenceFrames
.First(frame => frame.AttributeValue != null)
.AttributeEventHandlerId;
// Assert: Event not yet fired
Assert.Null(receivedArgs);
// Act/Assert: Event can be fired
var eventArgs = new UIMouseEventArgs();
renderer.DispatchEvent(componentId, eventHandlerId, eventArgs);
Assert.NotNull(receivedArgs);
}
[Fact]
public void CanDispatchEventsToNestedComponents()
{
@ -955,6 +983,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
{
public UIEventHandler OnTest { get; set; }
public UIMouseEventHandler OnClick { get; set; }
public Action OnClickAction { get; set; }
public bool SkipElement { get; set; }
private int renderCount = 0;
@ -974,11 +1003,15 @@ namespace Microsoft.AspNetCore.Blazor.Test
{
builder.AddAttribute(4, "onclick", OnClick);
}
if (OnClickAction != null)
{
builder.AddAttribute(5, "onclickaction", OnClickAction);
}
builder.CloseElement();
builder.CloseElement();
}
builder.CloseElement();
builder.AddContent(5, $"Render count: {++renderCount}");
builder.AddContent(6, $"Render count: {++renderCount}");
}
public void HandleEvent(UIEventHandler handler, UIEventArgs args)

View File

@ -1,5 +1,4 @@
@using System.Collections.Generic
@using Microsoft.AspNetCore.Blazor
Child components follow.
<button class="addChild" onclick="@AddChild">Add</button>
<button class="removeChild" onclick="@RemoveChild">Remove</button>
@ -13,13 +12,13 @@ Child components follow.
int numAdded = 0;
List<string> currentChildrenMessages = new List<string>();
void AddChild(UIMouseEventArgs e)
void AddChild()
{
numAdded++;
currentChildrenMessages.Add($"Child {numAdded}");
}
void RemoveChild(UIMouseEventArgs e)
void RemoveChild()
{
if (currentChildrenMessages.Count > 0)
{

View File

@ -64,7 +64,7 @@
enum SelectableValue { First, Second, Third, Fourth }
SelectableValue selectValue = SelectableValue.Second;
void AddAndSelectNewSelectOption(UIMouseEventArgs e)
void AddAndSelectNewSelectOption()
{
includeFourthOption = true;
selectValue = SelectableValue.Fourth;

View File

@ -1,7 +1,6 @@
@using Microsoft.AspNetCore.Blazor
<h1>Counter</h1>
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<p><button onclick="@((handleClicks ? (Action<UIMouseEventArgs>)IncrementCount : null))">Click me</button></p>
<p><button onclick="@((handleClicks ? (Action)IncrementCount : null))">Click me</button></p>
<label>
<input type="checkbox" bind="@handleClicks" />
@ -12,7 +11,7 @@
int currentCount = 0;
bool handleClicks = true;
void IncrementCount(UIMouseEventArgs e)
void IncrementCount()
{
currentCount++;
}

View File

@ -1,5 +1,4 @@
@using Microsoft.AspNetCore.Blazor
<h1>Counter</h1>
<h1>Counter</h1>
<!-- Note: passing 'Message' parameter with lowercase name to show it's case insensitive -->
<p>Current count: <MessageComponent message=@currentCount.ToString() /></p>
@ -9,7 +8,7 @@
@functions {
int currentCount = 0;
void IncrementCount(UIMouseEventArgs e)
void IncrementCount()
{
currentCount++;
}

View File

@ -1,5 +1,4 @@
@addTagHelper *, TestContentPackage
@using Microsoft.AspNetCore.Blazor
@using TestContentPackage
<h1>Functionality and content from an external package</h1>
@ -32,7 +31,7 @@
{
string result;
void ShowJavaScriptPrompt(UIMouseEventArgs e)
void ShowJavaScriptPrompt()
{
result = MyPrompt.Show("Hello!");
}

View File

@ -1,5 +1,4 @@
@using Microsoft.AspNetCore.Blazor
@inject System.Net.Http.HttpClient Http
@inject System.Net.Http.HttpClient Http
<h1>Cookie counter</h1>
<p>The server increments the count by one on each request.</p>
@ -18,13 +17,13 @@
string testServerBaseUrl;
string responseText;
async void DeleteCookie(UIMouseEventArgs e)
async void DeleteCookie()
{
await DoRequest("api/cookie/reset");
StateHasChanged();
}
async void GetAndIncrementCounter(UIMouseEventArgs e)
async void GetAndIncrementCounter()
{
await DoRequest("api/cookie/increment");
StateHasChanged();

View File

@ -1,6 +1,5 @@
@using System.Net
@using System.Net.Http
@using Microsoft.AspNetCore.Blazor
@using Microsoft.AspNetCore.Blazor.Browser.Http
@inject HttpClient Http
@ -72,7 +71,7 @@
string responseBody;
string responseHeaders;
async void DoRequest(UIMouseEventArgs e)
async void DoRequest()
{
responseStatusCode = null;
@ -125,7 +124,7 @@
StateHasChanged();
}
void AddHeader(UIMouseEventArgs e)
void AddHeader()
=> requestHeaders.Add(new RequestHeader());
void RemoveHeader(RequestHeader header)

View File

@ -1,5 +1,4 @@
@using Microsoft.AspNetCore.Blazor
<div class="special-style">
<div class="special-style">
This component, including the CSS and image required to produce its
elegant styling, is in an external NuGet package.
<button onclick="@ChangeLabel">@buttonLabel </button>
@ -8,7 +7,7 @@
@functions {
string buttonLabel = "Click me";
void ChangeLabel(UIMouseEventArgs e)
void ChangeLabel()
{
buttonLabel = "It works";
}