【问题标题】:Blazor EditForm Validation not working when using Child Component使用子组件时 Blazor EditForm 验证不起作用
【发布时间】:2020-06-16 13:22:46
【问题描述】:

我有一个名为 EditOffice 的 Blazor 组件。它看起来如下:

<EditForm Model="@Office" OnValidSubmit="@HandleValidSubmit">

    <DataAnnotationsValidator />
    <ValidationSummary />

    <InputTextRow Label="Name" @bind-Value="@Office.Name" Placeholder="Enter name" />
    <InputTextRow Label="ABN" @bind-Value="@Office.ABN" Placeholder="Enter ABN" />
...
    <button type="submit" class="btn btn-primary edit-btn">Save office</button>
</EditForm>

我创建了名为 InputTextRow 的子组件,试图整理我的代码。它们如下所示:

<div class="form-group row">
    <label for="@Id" class="col-sm-3">@Label: </label>
    <InputText id="@Id" @oninput="OnValueChanged" @bind-Value="@Value" class="form-control col-sm-8" placeholder="@Placeholder"></InputText>
    <ValidationMessage class="offset-sm-3 col-sm-8" For="@(() => Value)" />
</div>

@code {

    public string Id => Label.ToLower().Replace(" ", "");

    [Parameter]
    public string Label { get; set; }

    [Parameter]
    public string Value { get; set; }

    [Parameter]
    public string Placeholder { get; set; }

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

    Task OnValueChanged(ChangeEventArgs e)
    {
        Value = e.Value.ToString();
        return ValueChanged.InvokeAsync(Value);
    }
}

ValidationMessage 在我的子组件中不起作用。知道为什么吗?

【问题讨论】:

    标签: validation blazor


    【解决方案1】:

    我知道我来晚了,但这是我的答案:)

    所以现在有更好的解决方案。

    TL:DR 懒人解决方案

    请注意 - 这是实验性,但软件包已经在候选版本中,所以我想不用担心。

    使用Microsoft.AspNetCore.Components.DataAnnotations.Validation 包和&lt;ObjectGraphDataAnnotationsValidator /&gt; 而不是&lt;DataAnnotationsValidator /&gt; 并使用这个东西:

    using System.ComponentModel.DataAnnotations;
    
    public class YourComplexModel
    {
        // other properties
    
        [ValidateComplexType] // <--life saver
        public ChildModel ChildModel { get; set; } = new ChildModel();
    }
    

    来自 MS Docs 的片段

    链接Microsoft Docs:

    Blazor 支持使用内置 DataAnnotationsValidator 的数据注释来验证表单输入。但是,DataAnnotationsValidator 仅验证绑定到表单的模型的顶级属性,这些属性不是集合或复杂类型的属性。

    要验证绑定模型的整个对象图,包括集合类型和复杂类型属性,请使用实验性 Microsoft.AspNetCore.Components.DataAnnotations.Validation 包提供的 ObjectGraphDataAnnotationsValidator:

    <EditForm Model="@model" OnValidSubmit="@HandleValidSubmit">
        <ObjectGraphDataAnnotationsValidator />
        ...
    </EditForm>
    

    使用 [ValidateComplexType] 注释模型属性。在以下模型类中,ShipDescription 类包含额外的数据注释,用于验证模型何时绑定到表单:

    Starship.cs:

    using System;
    using System.ComponentModel.DataAnnotations;
    
    public class Starship
    {
        ...
    
        [ValidateComplexType]
        public ShipDescription ShipDescription { get; set; } = 
            new ShipDescription();
    
        ...
    }
    

    ShipDescription.cs:

    using System;
    using System.ComponentModel.DataAnnotations;
    
    public class ShipDescription
    {
        [Required]
        [StringLength(40, ErrorMessage = "Description too long (40 char).")]
        public string ShortDescription { get; set; }
    
        [Required]
        [StringLength(240, ErrorMessage = "Description too long (240 char).")]
        public string LongDescription { get; set; }
    }
    

    【讨论】:

    • 今天不存在,目前还有其他有效的解决方案吗?
    • 嗨@LiviuMihaianu。遗憾的是,我已经有一段时间没有与 Blazor 合作了。就我而言 - 它甚至适用于 .NET 5 的 RC 版本,但也许确实发生了一些变化。我会检查最近的 MS 博客中的命名空间是否有某种变化。除此之外 - 如果内置解决方案不起作用,请查看 Fluent validation for Blazor
    • 嗨@RafałKopczyński,你有机会去看看吗?无法从 vs 或 PM 控制台找到链接的 nuget 包
    【解决方案2】:

    我遇到了完全相同的问题。我的代码和你的非常相似。我的子组件进行了验证,但没有显示验证错误消息。

    我确实使用这种扩展方法:

    using System;
    using Microsoft.AspNetCore.Components.Forms;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    
    namespace TimeRecording.Extensions
    {
        public static class EditContextExtensions
        {
            static PropertyInfo IsModifiedProperty;
            static MethodInfo GetFieldStateMethod;
    
            /// <summary>
            /// Validates an entire object tree
            /// </summary>
            /// <param name="editContext">The EditContext to validate the Model of</param>
            /// <returns>True if valid, otherwise false</returns>
            public static bool ValidateObjectTree(this EditContext editContext)
            {
                var validatedObjects = new HashSet<object>();
                ValidateObject(editContext, editContext.Model, validatedObjects);
                editContext.NotifyValidationStateChanged();
                return !editContext.GetValidationMessages().Any();
            }
    
            public static void ValidateProperty(this EditContext editContext, FieldIdentifier fieldIdentifier)
            {
                if (fieldIdentifier.Model == null)
                    return;
    
                var propertyInfo = fieldIdentifier.Model.GetType().GetProperty(
                    fieldIdentifier.FieldName,
                    BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static);
    
                var validatedObjects = new HashSet<object>();
                ValidateProperty(editContext, fieldIdentifier.Model, propertyInfo, validatedObjects);
            }
    
            private static void ValidateObject(
                EditContext editContext,
                object instance,
                HashSet<object> validatedObjects)
            {
                if (instance == null)
                    return;
    
                if (validatedObjects.Contains(instance))
                    return;
    
                if (instance is IEnumerable && !(instance is string))
                {
                    foreach (object value in (IEnumerable)instance)
                        ValidateObject(editContext, value, validatedObjects);
                    return;
                }
    
                if (instance.GetType().Assembly == typeof(string).Assembly)
                    return;
    
                validatedObjects.Add(instance);
    
                var properties = instance.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                foreach (PropertyInfo property in properties)
                    ValidateProperty(editContext, instance, property, validatedObjects);
            }
    
            private static void ValidateProperty(
                EditContext editContext,
                object instance,
                PropertyInfo property,
                HashSet<object> validatedObjects)
            {
                NotifyPropertyChanged(editContext, instance, property.Name);
    
                object value = property.GetValue(instance);
                ValidateObject(editContext, value, validatedObjects);
            }
    
            private static void NotifyPropertyChanged(
                EditContext editContext,
                object instance,
                string propertyName)
            {
                if (GetFieldStateMethod == null)
                {
                    GetFieldStateMethod = editContext.GetType().GetMethod(
                        "GetFieldState",
                        BindingFlags.NonPublic | BindingFlags.Instance);
                }
    
                var fieldIdentifier = new FieldIdentifier(instance, propertyName);
                object fieldState = GetFieldStateMethod.Invoke(editContext, new object[] { fieldIdentifier, true });
    
                if (IsModifiedProperty == null)
                {
                    IsModifiedProperty = fieldState.GetType().GetProperty(
                        "IsModified",
                        BindingFlags.Public | BindingFlags.Instance);
                }
    
                object originalIsModified = IsModifiedProperty.GetValue(fieldState);
                editContext.NotifyFieldChanged(fieldIdentifier);
                IsModifiedProperty.SetValue(fieldState, originalIsModified);
            }
    
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-07-27
      • 2020-10-14
      • 2021-09-11
      • 1970-01-01
      • 2020-09-30
      • 2020-06-06
      • 2020-11-05
      • 2020-07-13
      • 2020-10-26
      相关资源
      最近更新 更多