Add support general delegate types
This builds upon existing support for UIEventHandler-typed component properties and applies the same principle to any delegate type. We try to help by generating the LSH of the lambda `=>` allowing you to write `OnClick="Foo()"` rather than `OnClick="(e) => Foo()"`. You can of course use @ as an escape. The only rough edge here is that if the parameter names aren't memorable for the delgate type, it's not super helpful.
This commit is contained in:
parent
d1cfe0191a
commit
c05657c7f2
|
|
@ -423,7 +423,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
// We don't expect this to happen, we just want to know if it can.
|
||||
throw new InvalidOperationException("Attribute nodes should either be minimized or a single content node.");
|
||||
}
|
||||
else if (node.BoundAttribute.IsUIEventHandlerProperty())
|
||||
else if (node.BoundAttribute.IsDelegateProperty())
|
||||
{
|
||||
// See the runtime version of this code for a thorough description of what we're doing here
|
||||
if ((cSharpNode = node.Children[0] as CSharpExpressionIntermediateNode) != null)
|
||||
|
|
@ -445,7 +445,9 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
context.CodeWriter.Write(" = ");
|
||||
context.CodeWriter.Write("new ");
|
||||
context.CodeWriter.Write(node.BoundAttribute.TypeName);
|
||||
context.CodeWriter.Write("(e => ");
|
||||
context.CodeWriter.Write("(");
|
||||
context.CodeWriter.Write(node.BoundAttribute.GetDelegateSignature());
|
||||
context.CodeWriter.Write(" => ");
|
||||
WriteCSharpToken(context, ((IntermediateToken)node.Children[0]));
|
||||
context.CodeWriter.Write(");");
|
||||
context.CodeWriter.WriteLine();
|
||||
|
|
|
|||
|
|
@ -470,7 +470,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
// We don't expect this to happen, we just want to know if it can.
|
||||
throw new InvalidOperationException("Attribute nodes should either be minimized or a single content node.");
|
||||
}
|
||||
else if (node.BoundAttribute.IsUIEventHandlerProperty())
|
||||
else if (node.BoundAttribute.IsDelegateProperty())
|
||||
{
|
||||
// This is a UIEventHandler property. We do some special code generation for this
|
||||
// case so that it's easier to write for common cases.
|
||||
|
|
@ -502,7 +502,8 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
context.CodeWriter.Write("new ");
|
||||
context.CodeWriter.Write(node.BoundAttribute.TypeName);
|
||||
context.CodeWriter.Write("(");
|
||||
context.CodeWriter.Write("e => ");
|
||||
context.CodeWriter.Write(node.BoundAttribute.GetDelegateSignature());
|
||||
context.CodeWriter.Write(" => ");
|
||||
context.CodeWriter.Write(((IntermediateToken)node.Children[0]).Content);
|
||||
context.CodeWriter.Write(")");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Razor.Language;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
|
|
@ -11,7 +12,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
{
|
||||
internal class ComponentTagHelperDescriptorProvider : RazorEngineFeatureBase, ITagHelperDescriptorProvider
|
||||
{
|
||||
public static readonly string UIEventHandlerPropertyMetadata = "Blazor.IsUIEventHandler";
|
||||
public static readonly string DelegateSignatureMetadata = "Blazor.DelegateSignature";
|
||||
|
||||
public readonly static string ComponentTagHelperKind = ComponentDocumentClassifierPass.ComponentDocumentKind;
|
||||
|
||||
|
|
@ -113,7 +114,11 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
|
||||
if (property.kind == PropertyKind.Delegate)
|
||||
{
|
||||
pb.Metadata.Add(UIEventHandlerPropertyMetadata, bool.TrueString);
|
||||
var propertyType = (INamedTypeSymbol)property.property.Type;
|
||||
var parameters = propertyType.DelegateInvokeMethod.Parameters;
|
||||
|
||||
var signature = "(" + string.Join(", ", parameters.Select(p => p.Name)) + ")";
|
||||
pb.Metadata.Add(DelegateSignatureMetadata, signature);
|
||||
}
|
||||
|
||||
xml = property.property.GetDocumentationCommentXml();
|
||||
|
|
@ -182,12 +187,8 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
kind = PropertyKind.Enum;
|
||||
}
|
||||
|
||||
if (kind == PropertyKind.Default &&
|
||||
property.Type.TypeKind == TypeKind.Delegate &&
|
||||
property.Type.ToDisplayString(FullNameTypeDisplayFormat) == BlazorApi.UIEventHandler.FullTypeName)
|
||||
if (kind == PropertyKind.Default && property.Type.TypeKind == TypeKind.Delegate)
|
||||
{
|
||||
// For delegate types we do some special code generation when the type
|
||||
// UIEventHandler.
|
||||
kind = PropertyKind.Delegate;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,17 +8,27 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
{
|
||||
internal static class TagHelperBoundAttributeDescriptorExtensions
|
||||
{
|
||||
public static bool IsUIEventHandlerProperty(this BoundAttributeDescriptor attribute)
|
||||
public static bool IsDelegateProperty(this BoundAttributeDescriptor attribute)
|
||||
{
|
||||
if (attribute == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(attribute));
|
||||
}
|
||||
|
||||
var key = ComponentTagHelperDescriptorProvider.UIEventHandlerPropertyMetadata;
|
||||
return
|
||||
attribute.Metadata.TryGetValue(key, out var value) &&
|
||||
string.Equals(value, bool.TrueString);
|
||||
var key = ComponentTagHelperDescriptorProvider.DelegateSignatureMetadata;
|
||||
return attribute.Metadata.TryGetValue(key, out var value);
|
||||
}
|
||||
|
||||
public static string GetDelegateSignature(this BoundAttributeDescriptor attribute)
|
||||
{
|
||||
if (attribute == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(attribute));
|
||||
}
|
||||
|
||||
var key = ComponentTagHelperDescriptorProvider.DelegateSignatureMetadata;
|
||||
attribute.Metadata.TryGetValue(key, out var value);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ global::System.Object __typeHelper = ""*, TestAssembly"";
|
|||
{
|
||||
base.BuildRenderTree(builder);
|
||||
|
||||
__o = new Microsoft.AspNetCore.Blazor.UIEventHandler(e =>
|
||||
__o = new Microsoft.AspNetCore.Blazor.UIEventHandler(eventArgs =>
|
||||
#line 2 ""x:\dir\subdir\Test\TestComponent.cshtml""
|
||||
Increment()
|
||||
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ namespace Test
|
|||
{
|
||||
base.BuildRenderTree(builder);
|
||||
builder.OpenComponent<Test.MyComponent>(0);
|
||||
builder.AddAttribute(1, ""OnClick"", new Microsoft.AspNetCore.Blazor.UIEventHandler(e => Increment()));
|
||||
builder.AddAttribute(1, ""OnClick"", new Microsoft.AspNetCore.Blazor.UIEventHandler(eventArgs => Increment()));
|
||||
builder.CloseComponent();
|
||||
builder.AddContent(2, ""\n\n"");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -282,8 +282,8 @@ namespace Test
|
|||
Assert.False(attribute.IsStringProperty);
|
||||
}
|
||||
|
||||
[Fact] // UIEventHandler properties have some special intellisense behavior
|
||||
public void Excecute_UIEventHandlerProperty_CreatesDescriptor()
|
||||
[Fact]
|
||||
public void Execute_DelegateProperty_CreatesDescriptor()
|
||||
{
|
||||
// Arrange
|
||||
|
||||
|
|
@ -326,7 +326,7 @@ namespace Test
|
|||
Assert.False(attribute.IsBooleanProperty);
|
||||
Assert.False(attribute.IsEnum);
|
||||
Assert.False(attribute.IsStringProperty);
|
||||
Assert.True(attribute.IsUIEventHandlerProperty());
|
||||
Assert.True(attribute.IsDelegateProperty());
|
||||
}
|
||||
|
||||
// For simplicity in testing, exlude the built-in components. We'll add more and we
|
||||
|
|
|
|||
Loading…
Reference in New Issue