首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在Blazor中动态设置ValidationMessage<TValue>.For属性?

如何在Blazor中动态设置ValidationMessage<TValue>.For属性?
EN

Stack Overflow用户
提问于 2020-12-21 13:50:48
回答 3查看 1.1K关注 0票数 4

文档的本节描述了如何显示验证消息。

代码语言:javascript
复制
<ValidationMessage For="() => Parameters.PropertyA"></ValidationMessage>      

如何动态设置ValidationMessage.For属性?

由于ForExpression<Func<TValue>>类型的,所以我想传递一个Func,但这不能编译:

代码语言:javascript
复制
[Parameter]
public Func<string> PropertyLocator { get; set; }

<ValidationMessage For="PropertyLocator"></ValidationMessage>

这将编译,但验证消息将无法正确解析。

代码语言:javascript
复制
<ValidationMessage For="() => PropertyLocator"></ValidationMessage>

我还试图使该组件具有通用性,以便它了解Parameters类型:

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Components;

public partial class MyComponent<TParam>
{
    [Parameter]
    public TParam Parameters { get; set; }

    [Parameter]
    public Func<TReportParam, string> PropertyLocator { get; set; }
}


@using System.Linq.Expressions
@typeparam TParam
<ValidationMessage For="@((Expression<Func<string>>)(() => PropertyLocator(this.Parameters)))"></ValidationMessage>


<MyComponent TParam="MyParameters" Parameters="BindToSomeValue" PropertyLocator="(parameters) => parameters.PropertyA" />

但这将导致以下运行时异常:

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer100未处理异常呈现组件:提供的表达式包含不支持的InvocationExpression1。FieldIdentifier只支持对象的简单成员访问器(字段、属性)。System.ArgumentException:提供的表达式包含不支持的InvocationExpression1。FieldIdentifier只支持对象的简单成员访问器(字段、属性)。在Microsoft.AspNetCore.Components.Forms.FieldIdentifier.ParseAccessor字符串 at Microsoft.AspNetCore.Components.Forms.FieldIdentifier.Create字符串 at Microsoft.AspNetCore.Components.Forms.ValidationMessage`1[System.String,System.Private.CoreLib,Version=5.0.0.0,Culture=neutral,PublicKeyToken=7cec85d7bea7798e].OnParametersSet() at Microsoft.AspNetCore.Components.ComponentBase.CallOnParametersSetAsync() at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-12-21 15:17:34

我创建了一个小样本页面。

该模型使用DataAnnotations作为验证机制。

代码语言:javascript
复制
    public class DemoInputModel
    {
        [Required]
        public String PropertyOne { get; set; }

        [MinLength(2)]
        public String PropertyTwo { get; set; }

        [MaxLength(5)]
        public String PropertyThree { get; set; }
    }

在页面上,模型被初始化并设置为编辑上下文。我们有三个文本输入和一个选择框。复选框可用于切换验证消息。如果复选框中的值被更改,则将为ValidationMessage分配一个新表达式。

代码语言:javascript
复制
@using System.ComponentModel.DataAnnotations;
@using System.Linq.Expressions;

@page "/test"


<h1>ValidationMessageTest</h1>

<EditForm Model="_model">
    <DataAnnotationsValidator />

    <ValidationMessage For="ValidationResolver"></ValidationMessage>

    <InputText @bind-Value="_model.PropertyOne" />
    <InputText @bind-Value="_model.PropertyTwo" />
    <InputText @bind-Value="_model.PropertyThree" />

    <InputSelect @bind-Value="SelectedValidationProperty">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
    </InputSelect>

    @*<ValidationSummary />*@

</EditForm>


@code {

    private DemoInputModel _model = new DemoInputModel
    {
        PropertyOne = "Test",
        PropertyTwo = "42",
        PropertyThree = "Math.PI",
    };

    private String _selectedValidationProperty;

    public String SelectedValidationProperty
    {
        get => _selectedValidationProperty;
        set
        {
            _selectedValidationProperty = value;
            ChangeValidator(value);
        }
    }

    public Expression<Func<String>> ValidationResolver { get; set; }

    protected override void OnInitialized()
    {
        SelectedValidationProperty = "1";
        base.OnInitialized();
    }

    public void ChangeValidator(String value)
    {
        switch (value)
        {
            case "1":
                ValidationResolver = () => _model.PropertyOne;
                break;
            case "2":
                ValidationResolver = () => _model.PropertyTwo;
                break;
            case "3":
                ValidationResolver = () => _model.PropertyThree;
                break;
            default:
                break;
        }
    }
}

你是说像这样的事吗?如果您的模型不只有字符串,就会变得稍微复杂一些,如示例中所示。“快速”解决方法可能是为每种可能的类型提供一个Expression

在遮罩下,表达式用于创建一个FieldIdentifier。然后使用FieldIdentifierEditContext获取相应的属性/字段,以检查验证状态。因此,您在为表达式选择什么方面受到限制。错误消息FieldIdentifier只支持对象的简单成员访问器(字段、属性),这很好地说明了这一限制。

票数 3
EN

Stack Overflow用户

发布于 2020-12-21 15:12:40

我想通过一个Func代替

为什么?如果没有特定的原因需要传递Func<TValue>而不是Expression<Func<TValue>>,那么只需使用参数

代码语言:javascript
复制
[Parameter]
public Expression<Func<string>> PropertyLocator { get; set; }

如果您只想要一个Func<>,因为您要将它重用为ValidationMessageFor参数以外的其他东西,那么您可以查看Extracting Func<> from Expression<>,以便从Expression<Func<string>> PropertyLocator获得Func<>

如果您真的想传递一个Func<>,那么在尝试将.net函数转换为.net表达式时,可能会遇到一些问题需要转换。

票数 1
EN

Stack Overflow用户

发布于 2021-02-18 15:15:44

在进行了一些研究之后,我无意中发现了以下blazor特性:

装订的神圣三位一体

阅读更多关于它的这里

简而言之,如果[Parameter]与折叠语法绑定.

代码语言:javascript
复制
<MyComponent @bind-Value="My.Binding.Path" />

..。它不仅支持双向绑定,而且还设置一个定位器表达式。

代码语言:javascript
复制
[Parameter]
public string Value { get; set; }

[Parameter]
public EventCallback<string> ValueChanged { get; set; }

[Parameter]
public Expression<Func<string>> ValueExpression { get; set; }

您可以使用任何类型,而不是string

由于ValueExpression的值是自动设置的,因此可以使用此行为显示绑定属性的验证消息。只需使用表达式将ValidationMessage组件添加到组件中即可。

代码语言:javascript
复制
<ValidationMessage For="ValueExpression" />

一点额外的

如果您正在构建一个支持验证的组件(此时,我假设您是这样的)。以下可能也是您感兴趣的。

不仅可以使用神圣的三位一体来显示验证消息,还可以创建支持验证的组件。有许多关于这个主题的文章。

简言之:

  • 构建组件
  • 随时通知EditContext上的字段更改

要使上面创建的MyComponentValue属性支持验证,只需遵循以下步骤。

定义一个CascadingParameter EditContext,这将获得当前的EditContext,通常来自EditForm组件。还请注意,如果没有EditContext,则可能不会设置CascadingValue。例如,如果组件未放置在EditForm

代码语言:javascript
复制
[CascadingParameter]
public EditContext? EditContext

定义一个属性来存储FieldIdentifier,并在设置参数时设置它。

代码语言:javascript
复制
public FieldIdentifier? FieldIdentifier { get; private set; }

public override async Task SetParametersAsync(ParameterView parameters)
{
    await base.SetParametersAsync(parameters);

    if (this.EditContext != null && this.DateExpression != null && this.FieldIdentifier?.Model != this.EditContext.Model)
    {
        this.FieldIdentifier = Microsoft.AspNetCore.Components.Forms.FieldIdentifier.Create(this.DateExpression);
    }
}

在需要时(通常在调用ValueChanged之后)触发字段的验证:

代码语言:javascript
复制
this.Value = value;
this.ValueChanged.InvokeAsync(this.Value);
if (this.FieldIdentifier?.FieldName != null)
{
    this.EditContext?.NotifyFieldChanged(this.FieldIdentifier!.Value);
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65393962

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档