Add [Parameter] for component parameters
This change introduces ParameterAttribute to specify a bindable component parameter. As of the 0.3 release of Blazor we plan to make [Parameter] required to make a property bindable by callers. This also applies to parameters when their value is set by the infrastructure, such as `Body` for layouts, and route paramters. The rationale behind this change is that we think there is a need to separate the definition of properties from their suitability for a caller to set them through markup. We plan to introduce more features in this area in the future such as marking parameters as required. This is first step, and we think that this approach will scale nicely as we add more functionaly. The 0.3 release seems like the right time to change this behavior since we're also introducing `ref` for captures in this release.
This commit is contained in:
parent
76bf82eb49
commit
f661021324
|
|
@ -15,5 +15,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@functions {
|
@functions {
|
||||||
|
[Parameter]
|
||||||
public RenderFragment Body { get; set; }
|
public RenderFragment Body { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,11 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
||||||
public static readonly string BuildRenderTree = nameof(BuildRenderTree);
|
public static readonly string BuildRenderTree = nameof(BuildRenderTree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ParameterAttribute
|
||||||
|
{
|
||||||
|
public static readonly string FullTypeName = "Microsoft.AspNetCore.Blazor.Components.ParameterAttribute";
|
||||||
|
}
|
||||||
|
|
||||||
public static class LayoutAttribute
|
public static class LayoutAttribute
|
||||||
{
|
{
|
||||||
public static readonly string FullTypeName = "Microsoft.AspNetCore.Blazor.Layouts.LayoutAttribute";
|
public static readonly string FullTypeName = "Microsoft.AspNetCore.Blazor.Layouts.LayoutAttribute";
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,13 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var parameterSymbol = compilation.GetTypeByMetadataName(BlazorApi.ParameterAttribute.FullTypeName);
|
||||||
|
if (parameterSymbol == null)
|
||||||
|
{
|
||||||
|
// No definition for [Parameter], nothing to do.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var types = new List<INamedTypeSymbol>();
|
var types = new List<INamedTypeSymbol>();
|
||||||
var visitor = new ComponentTypeVisitor(componentSymbol, types);
|
var visitor = new ComponentTypeVisitor(componentSymbol, types);
|
||||||
|
|
||||||
|
|
@ -60,17 +67,22 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
||||||
for (var i = 0; i < types.Count; i++)
|
for (var i = 0; i < types.Count; i++)
|
||||||
{
|
{
|
||||||
var type = types[i];
|
var type = types[i];
|
||||||
context.Results.Add(CreateDescriptor(type));
|
context.Results.Add(CreateDescriptor(type, parameterSymbol));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TagHelperDescriptor CreateDescriptor(INamedTypeSymbol type)
|
private TagHelperDescriptor CreateDescriptor(INamedTypeSymbol type, INamedTypeSymbol parameterSymbol)
|
||||||
{
|
{
|
||||||
if (type == null)
|
if (type == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(type));
|
throw new ArgumentNullException(nameof(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parameterSymbol == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(parameterSymbol));
|
||||||
|
}
|
||||||
|
|
||||||
var typeName = type.ToDisplayString(FullNameTypeDisplayFormat);
|
var typeName = type.ToDisplayString(FullNameTypeDisplayFormat);
|
||||||
var assemblyName = type.ContainingAssembly.Identity.Name;
|
var assemblyName = type.ContainingAssembly.Identity.Name;
|
||||||
|
|
||||||
|
|
@ -90,7 +102,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
||||||
// Components have very simple matching rules. The type name (short) matches the tag name.
|
// Components have very simple matching rules. The type name (short) matches the tag name.
|
||||||
builder.TagMatchingRule(r => r.TagName = type.Name);
|
builder.TagMatchingRule(r => r.TagName = type.Name);
|
||||||
|
|
||||||
foreach (var property in GetVisibleProperties(type))
|
foreach (var property in GetProperties(type, parameterSymbol))
|
||||||
{
|
{
|
||||||
if (property.kind == PropertyKind.Ignored)
|
if (property.kind == PropertyKind.Ignored)
|
||||||
{
|
{
|
||||||
|
|
@ -134,7 +146,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
||||||
// - has public getter
|
// - has public getter
|
||||||
// - has public setter
|
// - has public setter
|
||||||
// - is not an indexer
|
// - is not an indexer
|
||||||
private IEnumerable<(IPropertySymbol property, PropertyKind kind)> GetVisibleProperties(INamedTypeSymbol type)
|
private IEnumerable<(IPropertySymbol property, PropertyKind kind)> GetProperties(INamedTypeSymbol type, INamedTypeSymbol parameterSymbol)
|
||||||
{
|
{
|
||||||
var properties = new Dictionary<string, (IPropertySymbol, PropertyKind)>(StringComparer.Ordinal);
|
var properties = new Dictionary<string, (IPropertySymbol, PropertyKind)>(StringComparer.Ordinal);
|
||||||
do
|
do
|
||||||
|
|
@ -174,6 +186,12 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
||||||
kind = PropertyKind.Ignored;
|
kind = PropertyKind.Ignored;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!property.GetAttributes().Any(a => a.AttributeClass == parameterSymbol))
|
||||||
|
{
|
||||||
|
// Does not have [Parameter]
|
||||||
|
kind = PropertyKind.Ignored;
|
||||||
|
}
|
||||||
|
|
||||||
if (kind == PropertyKind.Default && property.Type.TypeKind == TypeKind.Enum)
|
if (kind == PropertyKind.Default && property.Type.TypeKind == TypeKind.Enum)
|
||||||
{
|
{
|
||||||
kind = PropertyKind.Enum;
|
kind = PropertyKind.Enum;
|
||||||
|
|
|
||||||
|
|
@ -14,5 +14,6 @@
|
||||||
@functions
|
@functions
|
||||||
{
|
{
|
||||||
// This is to demonstrate how a parent component can supply parameters
|
// This is to demonstrate how a parent component can supply parameters
|
||||||
|
[Parameter]
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,5 +14,6 @@
|
||||||
@functions
|
@functions
|
||||||
{
|
{
|
||||||
// This is to demonstrate how a parent component can supply parameters
|
// This is to demonstrate how a parent component can supply parameters
|
||||||
|
[Parameter]
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Blazor.Components
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Denotes the target member as a component parameter.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
|
||||||
|
public sealed class ParameterAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -66,6 +66,13 @@ namespace Microsoft.AspNetCore.Blazor.Components
|
||||||
$"matching the name '{propertyName}'.");
|
$"matching the name '{propertyName}'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!property.IsDefined(typeof(ParameterAttribute)))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Object of type '{targetType.FullName}' has a property matching the name '{propertyName}', " +
|
||||||
|
$"but it does not have [{nameof(ParameterAttribute)}] applied.");
|
||||||
|
}
|
||||||
|
|
||||||
return property;
|
return property;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,13 @@ namespace Microsoft.AspNetCore.Blazor.Layouts
|
||||||
/// Gets or sets the type of the page component to display.
|
/// Gets or sets the type of the page component to display.
|
||||||
/// The type must implement <see cref="IComponent"/>.
|
/// The type must implement <see cref="IComponent"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
public Type Page { get; set; }
|
public Type Page { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the parameters to pass to the page.
|
/// Gets or sets the parameters to pass to the page.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
public IDictionary<string, object> PageParameters { get; set; }
|
public IDictionary<string, object> PageParameters { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,13 @@ namespace Microsoft.AspNetCore.Blazor.Routing
|
||||||
/// Gets or sets the CSS class name applied to the NavLink when the
|
/// Gets or sets the CSS class name applied to the NavLink when the
|
||||||
/// current route matches the NavLink href.
|
/// current route matches the NavLink href.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
public string ActiveClass { get; set; }
|
public string ActiveClass { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value representing the URL matching behavior.
|
/// Gets or sets a value representing the URL matching behavior.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
public NavLinkMatch Match { get; set; }
|
public NavLinkMatch Match { get; set; }
|
||||||
|
|
||||||
[Inject] private IUriHelper UriHelper { get; set; }
|
[Inject] private IUriHelper UriHelper { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ namespace Microsoft.AspNetCore.Blazor.Routing
|
||||||
/// Gets or sets the assembly that should be searched, along with its referenced
|
/// Gets or sets the assembly that should be searched, along with its referenced
|
||||||
/// assemblies, for components matching the URI.
|
/// assemblies, for components matching the URI.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
public Assembly AppAssembly { get; set; }
|
public Assembly AppAssembly { get; set; }
|
||||||
|
|
||||||
private RouteTable Routes { get; set; }
|
private RouteTable Routes { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,10 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public int Value { get; set; }
|
public int Value { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public Action<int> ValueChanged { get; set; }
|
public Action<int> ValueChanged { get; set; }
|
||||||
}
|
}
|
||||||
}"));
|
}"));
|
||||||
|
|
@ -96,8 +98,10 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public int Value { get; set; }
|
public int Value { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public Action<int> OnChanged { get; set; }
|
public Action<int> OnChanged { get; set; }
|
||||||
}
|
}
|
||||||
}"));
|
}"));
|
||||||
|
|
|
||||||
|
|
@ -57,10 +57,10 @@ namespace Test
|
||||||
|
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
public int IntProperty { get; set; }
|
[Parameter] public int IntProperty { get; set; }
|
||||||
public bool BoolProperty { get; set; }
|
[Parameter] public bool BoolProperty { get; set; }
|
||||||
public string StringProperty { get; set; }
|
[Parameter] public string StringProperty { get; set; }
|
||||||
public SomeType ObjectProperty { get; set; }
|
[Parameter] public SomeType ObjectProperty { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"));
|
"));
|
||||||
|
|
@ -90,6 +90,36 @@ namespace Test
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Render_ChildComponent_TriesToSetNonParamter()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
AdditionalSyntaxTrees.Add(Parse(@"
|
||||||
|
using Microsoft.AspNetCore.Blazor.Components;
|
||||||
|
|
||||||
|
namespace Test
|
||||||
|
{
|
||||||
|
public class MyComponent : BlazorComponent
|
||||||
|
{
|
||||||
|
public int IntProperty { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"));
|
||||||
|
|
||||||
|
var component = CompileToComponent(@"
|
||||||
|
@addTagHelper *, TestAssembly
|
||||||
|
<MyComponent IntProperty=""123"" />");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var ex = Assert.Throws<InvalidOperationException>(() => GetRenderTree(component));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(
|
||||||
|
"Object of type 'Test.MyComponent' has a property matching the name 'IntProperty', " +
|
||||||
|
"but it does not have [ParameterAttribute] applied.",
|
||||||
|
ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Render_ChildComponent_WithExplicitStringParameter()
|
public void Render_ChildComponent_WithExplicitStringParameter()
|
||||||
{
|
{
|
||||||
|
|
@ -101,6 +131,7 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public string StringProperty { get; set; }
|
public string StringProperty { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -174,6 +205,7 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public Action<UIMouseEventArgs> OnClick { get; set; }
|
public Action<UIMouseEventArgs> OnClick { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -221,6 +253,7 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public Action<UIEventArgs> OnClick { get; set; }
|
public Action<UIEventArgs> OnClick { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -267,6 +300,7 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public bool BoolProperty { get; set; }
|
public bool BoolProperty { get; set; }
|
||||||
}
|
}
|
||||||
}"));
|
}"));
|
||||||
|
|
@ -296,7 +330,10 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public string MyAttr { get; set; }
|
public string MyAttr { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public RenderFragment ChildContent { get; set; }
|
public RenderFragment ChildContent { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -338,6 +375,7 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public RenderFragment ChildContent { get; set; }
|
public RenderFragment ChildContent { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using Microsoft.CodeAnalysis.CSharp;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Blazor.Build.Test
|
namespace Microsoft.AspNetCore.Blazor.Build.Test
|
||||||
|
|
@ -27,10 +26,10 @@ namespace Test
|
||||||
|
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
public int IntProperty { get; set; }
|
[Parameter] public int IntProperty { get; set; }
|
||||||
public bool BoolProperty { get; set; }
|
[Parameter] public bool BoolProperty { get; set; }
|
||||||
public string StringProperty { get; set; }
|
[Parameter] public string StringProperty { get; set; }
|
||||||
public SomeType ObjectProperty { get; set; }
|
[Parameter] public SomeType ObjectProperty { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"));
|
"));
|
||||||
|
|
@ -61,6 +60,7 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public string StringProperty { get; set; }
|
public string StringProperty { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -116,6 +116,7 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public Action<UIEventArgs> OnClick { get; set; }
|
public Action<UIEventArgs> OnClick { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -152,6 +153,7 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public Action<UIEventArgs> OnClick { get; set; }
|
public Action<UIEventArgs> OnClick { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -188,8 +190,10 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public string MyAttr { get; set; }
|
public string MyAttr { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public RenderFragment ChildContent { get; set; }
|
public RenderFragment ChildContent { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -382,8 +386,10 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public int Value { get; set; }
|
public int Value { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public Action<int> ValueChanged { get; set; }
|
public Action<int> ValueChanged { get; set; }
|
||||||
}
|
}
|
||||||
}"));
|
}"));
|
||||||
|
|
@ -446,8 +452,10 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public int Value { get; set; }
|
public int Value { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public Action<int> OnChanged { get; set; }
|
public Action<int> OnChanged { get; set; }
|
||||||
}
|
}
|
||||||
}"));
|
}"));
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,7 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
||||||
|
|
||||||
public class TestLayout : ILayoutComponent
|
public class TestLayout : ILayoutComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public RenderFragment Body { get; set; }
|
public RenderFragment Body { get; set; }
|
||||||
|
|
||||||
public void Init(RenderHandle renderHandle)
|
public void Init(RenderHandle renderHandle)
|
||||||
|
|
|
||||||
|
|
@ -51,10 +51,10 @@ namespace Test
|
||||||
|
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
public int IntProperty { get; set; }
|
[Parameter] public int IntProperty { get; set; }
|
||||||
public bool BoolProperty { get; set; }
|
[Parameter] public bool BoolProperty { get; set; }
|
||||||
public string StringProperty { get; set; }
|
[Parameter] public string StringProperty { get; set; }
|
||||||
public SomeType ObjectProperty { get; set; }
|
[Parameter] public SomeType ObjectProperty { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"));
|
"));
|
||||||
|
|
@ -85,6 +85,7 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public string StringProperty { get; set; }
|
public string StringProperty { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -141,6 +142,7 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public Action<UIEventArgs> OnClick { get; set; }
|
public Action<UIEventArgs> OnClick { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -177,6 +179,7 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public Action<UIEventArgs> OnClick { get; set; }
|
public Action<UIEventArgs> OnClick { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -213,8 +216,10 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public string MyAttr { get; set; }
|
public string MyAttr { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public RenderFragment ChildContent { get; set; }
|
public RenderFragment ChildContent { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -635,8 +640,10 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public int Value { get; set; }
|
public int Value { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public Action<int> ValueChanged { get; set; }
|
public Action<int> ValueChanged { get; set; }
|
||||||
}
|
}
|
||||||
}"));
|
}"));
|
||||||
|
|
@ -699,8 +706,10 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public int Value { get; set; }
|
public int Value { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public Action<int> OnChanged { get; set; }
|
public Action<int> OnChanged { get; set; }
|
||||||
}
|
}
|
||||||
}"));
|
}"));
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,10 @@ namespace Test
|
||||||
|
|
||||||
public void SetParameters(ParameterCollection parameters) { }
|
public void SetParameters(ParameterCollection parameters) { }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public string MyProperty { get; set; }
|
public string MyProperty { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public Action<string> MyPropertyChanged { get; set; }
|
public Action<string> MyPropertyChanged { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ namespace Test
|
||||||
|
|
||||||
public void SetParameters(ParameterCollection parameters) { }
|
public void SetParameters(ParameterCollection parameters) { }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public string MyProperty { get; set; }
|
public string MyProperty { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -136,6 +137,7 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public string MyProperty { get; set; }
|
public string MyProperty { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -176,6 +178,7 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public bool MyProperty { get; set; }
|
public bool MyProperty { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -227,6 +230,7 @@ namespace Test
|
||||||
|
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public MyEnum MyProperty { get; set; }
|
public MyEnum MyProperty { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -274,6 +278,7 @@ namespace Test
|
||||||
{
|
{
|
||||||
public class MyComponent : BlazorComponent
|
public class MyComponent : BlazorComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public Action<UIMouseEventArgs> OnClick { get; set; }
|
public Action<UIMouseEventArgs> OnClick { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -307,5 +312,61 @@ namespace Test
|
||||||
Assert.False(attribute.IsStringProperty);
|
Assert.False(attribute.IsStringProperty);
|
||||||
Assert.True(attribute.IsDelegateProperty());
|
Assert.True(attribute.IsDelegateProperty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact] // This component has lots of properties that don't become components.
|
||||||
|
public void Execute_IgnoredProperties_CreatesDescriptor()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
|
||||||
|
var compilation = BaseCompilation.AddSyntaxTrees(Parse(@"
|
||||||
|
using Microsoft.AspNetCore.Blazor.Components;
|
||||||
|
|
||||||
|
namespace Test
|
||||||
|
{
|
||||||
|
public abstract class MyBase : BlazorComponent
|
||||||
|
{
|
||||||
|
[Parameter]
|
||||||
|
public string Hidden { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MyComponent : MyBase
|
||||||
|
{
|
||||||
|
[Parameter]
|
||||||
|
public string NoPublicGetter { private get; set; }
|
||||||
|
|
||||||
|
public string NoParameterAttribute { get; set; }
|
||||||
|
|
||||||
|
// No attribute here, hides base-class property of the same name.
|
||||||
|
public new int Hidden { get; set; }
|
||||||
|
|
||||||
|
public string this[int i]
|
||||||
|
{
|
||||||
|
get { throw null; }
|
||||||
|
set { throw null; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"));
|
||||||
|
|
||||||
|
Assert.Empty(compilation.GetDiagnostics());
|
||||||
|
|
||||||
|
var context = TagHelperDescriptorProviderContext.Create();
|
||||||
|
context.SetCompilation(compilation);
|
||||||
|
|
||||||
|
var provider = new ComponentTagHelperDescriptorProvider();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
provider.Execute(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var components = ExcludeBuiltInComponents(context);
|
||||||
|
var component = Assert.Single(components);
|
||||||
|
|
||||||
|
Assert.Equal("TestAssembly", component.AssemblyName);
|
||||||
|
Assert.Equal("Test.MyComponent", component.Name);
|
||||||
|
|
||||||
|
Assert.Empty(component.BoundAttributes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Blazor.Components;
|
||||||
using Microsoft.AspNetCore.Blazor.Layouts;
|
using Microsoft.AspNetCore.Blazor.Layouts;
|
||||||
using Microsoft.AspNetCore.Blazor.RenderTree;
|
using Microsoft.AspNetCore.Blazor.RenderTree;
|
||||||
using Microsoft.AspNetCore.Blazor.Test.Helpers;
|
using Microsoft.AspNetCore.Blazor.Test.Helpers;
|
||||||
|
|
@ -219,6 +220,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
||||||
|
|
||||||
private class RootLayout : AutoRenderComponent, ILayoutComponent
|
private class RootLayout : AutoRenderComponent, ILayoutComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public RenderFragment Body { get; set; }
|
public RenderFragment Body { get; set; }
|
||||||
|
|
||||||
protected override void BuildRenderTree(RenderTreeBuilder builder)
|
protected override void BuildRenderTree(RenderTreeBuilder builder)
|
||||||
|
|
@ -232,6 +234,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
||||||
[Layout(typeof(RootLayout))]
|
[Layout(typeof(RootLayout))]
|
||||||
private class NestedLayout : AutoRenderComponent, ILayoutComponent
|
private class NestedLayout : AutoRenderComponent, ILayoutComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public RenderFragment Body { get; set; }
|
public RenderFragment Body { get; set; }
|
||||||
|
|
||||||
protected override void BuildRenderTree(RenderTreeBuilder builder)
|
protected override void BuildRenderTree(RenderTreeBuilder builder)
|
||||||
|
|
|
||||||
|
|
@ -1503,12 +1503,23 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
||||||
|
|
||||||
private class FakeComponent : IComponent
|
private class FakeComponent : IComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public int IntProperty { get; set; }
|
public int IntProperty { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public string StringProperty { get; set; }
|
public string StringProperty { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public object ObjectProperty { get; set; }
|
public object ObjectProperty { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public string ReadonlyProperty { get; private set; }
|
public string ReadonlyProperty { get; private set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
private string PrivateProperty { get; set; }
|
private string PrivateProperty { get; set; }
|
||||||
|
|
||||||
|
public string NonParameterProperty { get; set; }
|
||||||
|
|
||||||
public void Init(RenderHandle renderHandle) { }
|
public void Init(RenderHandle renderHandle) { }
|
||||||
public void SetParameters(ParameterCollection parameters)
|
public void SetParameters(ParameterCollection parameters)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1109,6 +1109,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
||||||
|
|
||||||
private class MessageComponent : AutoRenderComponent
|
private class MessageComponent : AutoRenderComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public string Message { get; set; }
|
public string Message { get; set; }
|
||||||
|
|
||||||
protected override void BuildRenderTree(RenderTreeBuilder builder)
|
protected override void BuildRenderTree(RenderTreeBuilder builder)
|
||||||
|
|
@ -1119,9 +1120,15 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
||||||
|
|
||||||
private class FakeComponent : IComponent
|
private class FakeComponent : IComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public int IntProperty { get; set; }
|
public int IntProperty { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public string StringProperty { get; set; }
|
public string StringProperty { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public object ObjectProperty { get; set; }
|
public object ObjectProperty { get; set; }
|
||||||
|
|
||||||
public RenderHandle RenderHandle { get; private set; }
|
public RenderHandle RenderHandle { get; private set; }
|
||||||
|
|
||||||
public void Init(RenderHandle renderHandle)
|
public void Init(RenderHandle renderHandle)
|
||||||
|
|
@ -1133,8 +1140,13 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
||||||
|
|
||||||
private class EventComponent : AutoRenderComponent, IComponent, IHandleEvent
|
private class EventComponent : AutoRenderComponent, IComponent, IHandleEvent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public Action<UIEventArgs> OnTest { get; set; }
|
public Action<UIEventArgs> OnTest { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public Action<UIMouseEventArgs> OnClick { get; set; }
|
public Action<UIMouseEventArgs> OnClick { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public Action OnClickAction { get; set; }
|
public Action OnClickAction { get; set; }
|
||||||
|
|
||||||
public bool SkipElement { get; set; }
|
public bool SkipElement { get; set; }
|
||||||
|
|
@ -1174,7 +1186,10 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
||||||
|
|
||||||
private class ConditionalParentComponent<T> : AutoRenderComponent where T : IComponent
|
private class ConditionalParentComponent<T> : AutoRenderComponent where T : IComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public bool IncludeChild { get; set; }
|
public bool IncludeChild { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public IDictionary<string, object> ChildParameters { get; set; }
|
public IDictionary<string, object> ChildParameters { get; set; }
|
||||||
|
|
||||||
protected override void BuildRenderTree(RenderTreeBuilder builder)
|
protected override void BuildRenderTree(RenderTreeBuilder builder)
|
||||||
|
|
@ -1199,6 +1214,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
||||||
|
|
||||||
private class ReRendersParentComponent : AutoRenderComponent
|
private class ReRendersParentComponent : AutoRenderComponent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public TestComponent Parent { get; set; }
|
public TestComponent Parent { get; set; }
|
||||||
private bool _isFirstTime = true;
|
private bool _isFirstTime = true;
|
||||||
|
|
||||||
|
|
@ -1216,6 +1232,7 @@ namespace Microsoft.AspNetCore.Blazor.Test
|
||||||
|
|
||||||
private class RendersSelfAfterEventComponent : IComponent, IHandleEvent
|
private class RendersSelfAfterEventComponent : IComponent, IHandleEvent
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public Action<object> OnClick { get; set; }
|
public Action<object> OnClick { get; set; }
|
||||||
|
|
||||||
private RenderHandle _renderHandle;
|
private RenderHandle _renderHandle;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<span style="color: red" class="message">@Message</span>
|
@using Microsoft.AspNetCore.Blazor.Components
|
||||||
|
<span style="color: red" class="message">@Message</span>
|
||||||
@functions {
|
@functions {
|
||||||
public string Message { get; set; }
|
[Parameter] public string Message { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
@using Microsoft.AspNetCore.Blazor
|
@using Microsoft.AspNetCore.Blazor
|
||||||
|
@using Microsoft.AspNetCore.Blazor.Components
|
||||||
@ChildContent
|
@ChildContent
|
||||||
@functions {
|
@functions {
|
||||||
// Note: The lack of any whitespace or other output besides @ChildContent is important for
|
// Note: The lack of any whitespace or other output besides @ChildContent is important for
|
||||||
// what scenarios this component is used for in E2E tests.
|
// what scenarios this component is used for in E2E tests.
|
||||||
|
|
||||||
public RenderFragment ChildContent { get; set; }
|
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
<div class="supplied">You supplied: @SuppliedValue</div>
|
@using Microsoft.AspNetCore.Blazor.Components
|
||||||
|
<div class="supplied">You supplied: @SuppliedValue</div>
|
||||||
<div class="computed">I computed: @computedValue</div>
|
<div class="computed">I computed: @computedValue</div>
|
||||||
|
|
||||||
@functions {
|
@functions {
|
||||||
|
[Parameter]
|
||||||
public int SuppliedValue { get; set; }
|
public int SuppliedValue { get; set; }
|
||||||
|
|
||||||
private int computedValue;
|
private int computedValue;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
@page "/RouterTest/WithParameters/Name/{firstName}/LastName/{lastName}"
|
@page "/RouterTest/WithParameters/Name/{firstName}/LastName/{lastName}"
|
||||||
@using BasicTestApp.RouterTest
|
@using BasicTestApp.RouterTest
|
||||||
|
@using Microsoft.AspNetCore.Blazor.Components
|
||||||
<div id="test-info">Your full name is @FirstName @LastName.</div>
|
<div id="test-info">Your full name is @FirstName @LastName.</div>
|
||||||
<Links />
|
<Links />
|
||||||
|
|
||||||
@functions
|
@functions
|
||||||
{
|
{
|
||||||
|
[Parameter]
|
||||||
public string FirstName { get; set; }
|
public string FirstName { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
public string LastName { get ; set; }
|
public string LastName { get ; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue