Blazor ValidationMessageStore是否有任何错误消息可检查?

4

我使用ValidationMessageStore按照这种格式验证我的Blazor表单输入:

https://learn.microsoft.com/en-us/aspnet/core/blazor/forms-validation?view=aspnetcore-5.0#basic-validation-1

然后在每个控件上输出ValidationMessage。

但是由于表单很长,因此我还想在提交按钮附近的某个地方指示给用户有一些错误需要修复,这就是为什么我们没有接受输入的原因。

我知道可以使用ValidationSummary,但我不想重复所有可能的错误,只需添加一个说明即可。

显然,ValidationMessageStore在内部保持了所有消息的集合,但它们是不可访问的。是否有可能检查是否存在任何错误消息?

3个回答

6

我找到了一个更简单的解决方案。在EditContext中,我找到了一个名为GetValidationMessages的方法。

@if (editContext.GetValidationMessages().Any())
{
    <div class="alert alert-danger">
        Some input was incomplete. Please review detailed messages above.
    </div>
}

1

我几乎有同样的问题。基于Jakob Lithner的答案,这是我想出的解决方案。

为了访问ValidationSummary是否有任何错误消息,您可以将EditForm绑定到EditContext而不是Model。这样,您可以直接在程序中引用上下文。这是一个使用模型对象和razor文件的简单示例,它将在验证每个表单时显示验证消息,并在任一表单无效时显示一般错误消息。

ExampleModel.cs

using System.ComponentModel.DataAnnotations;

namespace Example.Pages;

public class ExampleModel
{
    [Required(ErrorMessage = "The object must have a name")]
    [StringLength(100, ErrorMessage = "Object names cannot exceed 100 characters")]
    public string Name { get; set; } = "New Example";
    [StringLength(1000, ErrorMessage = "Description cannot exceed 1000 characters")]
    public string Description { get; set; }
}

ExamplePage.razor

@page "/ExamplePage"

<EditForm EditContext="@EditContext" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator/>

    @* Where the edit context is checked for validation messages. *@
    @* This can go anywhere you want it. *@
    @* An alternative to "alert alert-danger" is "validation-message", 
        which contains the style for validation messages *@
    @if (EditContext is not null && EditContext.GetValidationMessages().Any())
    {
        <p class="alert alert-danger text-center">
            One or more errors must be fixed before changes can be saved
        </p>
    }
    
    <div class="mb-3">
        <div class="input-group">
            <span class="input-group-text">Name</span>
            <InputText class="form-control" @bind-Value="ExampleModel.Name"/>
        </div>
        <ValidationMessage For="@(() => ExampleModel.Name)"/>
    </div>

    <div class="mb-3">
        <label class="form-label" for="queryDescription">Object Description</label>
        <InputTextArea 
            class="form-control" 
            id="queryDescription" rows="3" 
            @bind-Value="ExampleModel.Description"/>
        <ValidationMessage For="() => ExampleModel.Description"/>
    </div>

    <div class="btn-group">
        <a class="btn btn-warning" href="/ExamplePage">Cancel</a>
        @* By signifying the type as submit, this is the button that triggers
            the validation event *@
        <button class="btn btn-success" type="submit">Create</button>
    </div>
</EditForm>

@code {
    private ExampleModel ExampleModel { get; set; } = new();
    private EditContext? EditContext { get; set; }

    protected override Task OnInitializedAsync()
    {
        // This binds the Model to the Context
        EditContext = new EditContext(ExampleModel);
        return Task.CompletedTask;
    }

    private void HandleValidSubmit()
    {
        // Process the valid form
    }
}

有关如何使用Context而不是Model来使用EditForm,请参阅绑定表单中的表单和验证文档部分以获取更多详细信息。


1
请看ValidationSummary代码——验证信息存储是可用的。它并不是很复杂,所以你应该能够构建一个类似但更简单的组件来显示你想要的内容。
代码在这里:https://github.com/dotnet/aspnetcore/blob/main/src/Components/Web/src/Forms/ValidationSummary.cs
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Components.Rendering;

namespace Microsoft.AspNetCore.Components.Forms
{
    // Note: there's no reason why developers strictly need to use this. It's equally valid to
    // put a @foreach(var message in context.GetValidationMessages()) { ... } inside a form.
    // This component is for convenience only, plus it implements a few small perf optimizations.

    /// <summary>
    /// Displays a list of validation messages from a cascaded <see cref="EditContext"/>.
    /// </summary>
    public class ValidationSummary : ComponentBase, IDisposable
    {
        private EditContext? _previousEditContext;
        private readonly EventHandler<ValidationStateChangedEventArgs> _validationStateChangedHandler;

        /// <summary>
        /// Gets or sets the model to produce the list of validation messages for.
        /// When specified, this lists all errors that are associated with the model instance.
        /// </summary>
        [Parameter] public object? Model { get; set; }

        /// <summary>
        /// Gets or sets a collection of additional attributes that will be applied to the created <c>ul</c> element.
        /// </summary>
        [Parameter(CaptureUnmatchedValues = true)] public IReadOnlyDictionary<string, object>? AdditionalAttributes { get; set; }

        [CascadingParameter] EditContext CurrentEditContext { get; set; } = default!;

        /// <summary>`
        /// Constructs an instance of <see cref="ValidationSummary"/>.
        /// </summary>
        public ValidationSummary()
        {
            _validationStateChangedHandler = (sender, eventArgs) => StateHasChanged();
        }

        /// <inheritdoc />
        protected override void OnParametersSet()
        {
            if (CurrentEditContext == null)
            {
                throw new InvalidOperationException($"{nameof(ValidationSummary)} requires a cascading parameter " +
                    $"of type {nameof(EditContext)}. For example, you can use {nameof(ValidationSummary)} inside " +
                    $"an {nameof(EditForm)}.");
            }

            if (CurrentEditContext != _previousEditContext)
            {
                DetachValidationStateChangedListener();
                CurrentEditContext.OnValidationStateChanged += _validationStateChangedHandler;
                _previousEditContext = CurrentEditContext;
            }
        }

        /// <inheritdoc />
        protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
            // As an optimization, only evaluate the messages enumerable once, and
            // only produce the enclosing <ul> if there's at least one message
            var validationMessages = Model is null ?
                CurrentEditContext.GetValidationMessages() :
                CurrentEditContext.GetValidationMessages(new FieldIdentifier(Model, string.Empty));

            var first = true;
            foreach (var error in validationMessages)
            {
                if (first)
                {
                    first = false;

                    builder.OpenElement(0, "ul");
                    builder.AddMultipleAttributes(1, AdditionalAttributes);
                    builder.AddAttribute(2, "class", "validation-errors");
                }

                builder.OpenElement(3, "li");
                builder.AddAttribute(4, "class", "validation-message");
                builder.AddContent(5, error);
                builder.CloseElement();
            }

            if (!first)
            {
                // We have at least one validation message.
                builder.CloseElement();
            }
        }

        /// <inheritdoc/>
        protected virtual void Dispose(bool disposing)
        {
        }

        void IDisposable.Dispose()
        {
            DetachValidationStateChangedListener();
            Dispose(disposing: true);
        }

        private void DetachValidationStateChangedListener()
        {
            if (_previousEditContext != null)
            {
                _previousEditContext.OnValidationStateChanged -= _validationStateChangedHandler;
            }
        }
    }
}

如果您需要在构建组件方面获得更多帮助,请在问题中添加更多详细信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接