Как заставить EditContext.Validate() работать при привязке EditForm к массиву

#blazor #blazor-server-side

#blazor #blazor-на стороне сервера

Вопрос:

Я создал EditForm обертку таблицы следующим образом:

 **Index.razor**


@using System.ComponentModel.DataAnnotations;

<EditForm @ref="Form" Model="vms" OnSubmit="Submit">
    <DataAnnotationsValidator></DataAnnotationsValidator>
    <table class="table">
        <thead>
            <tr>
                <th>Code</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var vm in vms)
            {
                <tr>
                    <td>
                        <InputText @bind-Value="vm.Code"></InputText>
                        <ValidationMessage For="@(() => vm.Code)"></ValidationMessage>
                    </td>
                </tr>
            }
        </tbody>
    </table>
    <input type="submit" class="btn btn-primary" value="Submit" />
</EditForm>

@code{
    List<MyClass> vms;
    EditForm Form;
    class MyClass
    {
        [Required(ErrorMessage ="Required")]
        public string Code { get; set; }
    }
    protected override void OnInitialized()
    {
        vms = new List<MyClass>()
    {
            new MyClass()
            {
                Code = "1111"
            },
            new MyClass()
            {
                Code = "2222"
            }
        };
    }
    private void Submit()
    {
        bool IsValid = Form.EditContext.Validate();
    }
}
 

Сообщение об ошибке появляется правильно, как показано на рисунке ниже:

введите описание изображения здесь

Однако, когда я отправляю форму, а затем проверяю, она, похоже, не распознает недопустимое состояние.

введите описание изображения здесь

Он по-прежнему возвращает значение true после вызова EditContext.Validate() , даже несмотря на наличие ошибок.

Как мне заставить это работать? (Как мне получить false, если хотя бы один элемент модели в контексте EditForm является недопустимым, чтобы я мог выполнить другие действия по проверке?)


[Обновлено 2021-01-16] Ответы также можно найти здесь. https://www.pragimtech.com/blog/blazor/validating-complex-models-in-blazor /

Короче говоря, встроенная функция DataAnnotationValidation не работает с массивами. Чтобы заставить его работать, вы должны

  1. Установите Microsoft.AspNetCore.Компоненты.Примечания к данным.Проверка
  2. Сделайте массив атрибутом, а затем украсьте его [ValidateComplexType]
  3. Используйте ObjectGraphDataAnnotationsValidator

Комментарии:

1. По этой ссылке: docs.microsoft.com/en-us/aspnet/core/blazor /… , вы должны создать новый EditContext в процедуре OnInitialized() для формы (editContext = новый EditContext(vms). Возможно, это поможет вам

2. Я согласен с @JasonD , тогда, когда вы хотите проверить, что вы могли бы использовать: if (editContext .Validate()) {//SomeLogic}

Ответ №1:

Во-первых, я бы посоветовал вам сделать что-то вроде этого

 <EditForm EditContext="editContext" OnSubmit="Submit">
 

Вместо

 <EditForm @ref="Form" Model="vms" OnSubmit="Submit">
 

Что требует от вас определения EditContext следующим образом: EditContext editContext;

И создайте экземпляр объекта EditContext в инициализированном методе следующим образом:

 protected override void OnInitialized()
    {
        vms = new List<MyClass>() { new MyClass() { Code = "1111" },
                                    new MyClass() { Code = "2222" }
                                  };

        editContext = new EditContext(vms);
    }
 

Кстати, почему вы используете OnSubmit вместо OnValidSubmit and OnInvalidSubmit ? Вы ищете проблемы?

EditContext.Validate() возвращает неправильные результаты

Это неверно…

Проблема в том, что вы пытаетесь выполнить привязку к массиву MyClass…Но вы должны привязываться к одному объекту. Привязка к массиву возможна, но я не могу расширить ее, поскольку она заслуживает нового вопроса. Достаточно сказать, что массив объектов, к которым вы можете привязаться, сам по себе должен быть полем (свойством) одного ограниченного объекта, например, объекта Student, который содержит список языков, на которых он говорит.

Чтобы проверить вышеизложенное, измените List<MyClass> vms;

в MyClass model = new MyClass();

и editContext = new EditContext(vms);

в editContext = new EditContext(model);

и вместо

  @foreach (var vm in vms)
  {
            <tr>
                <td>
                    <InputText @bind-Value="vm.Code"></InputText>
                    <ValidationMessage For="@(() => vm.Code)"> 
       </ValidationMessage>
                </td>
            </tr>
  }
 

закодируйте это:

 <tr>
     <td>
        <InputText @bind-Value="model.Code"></InputText>
        <ValidationMessage For="@(() => model.Code)"></ValidationMessage>
     </td>
 </tr>
 

Теперь запустите свой код и проверьте, была ли EditContext.Validate() оправдана диффамация.

Обновить

В следующем примере кода описывается, как выполнить привязку к коллекции в EditForm и как проверить эту коллекцию, а также другие поля в модели, членом которой является эта коллекция.

Примечание: Вы должны выполнить Install-Package Microsoft.AspNetCore.Components.DataAnnotations.Validation -Version 3.2.0-rc1.20223.4 в вашем Package ManagerConsole, чтобы получить доступ к объектам, необходимым для выполнения примера…

 @page "/"
@using Microsoft.AspNetCore.Components.Forms
@using System.ComponentModel.DataAnnotations;

<EditForm EditContext="EditContext" OnSubmit="@OnSubmitHandler">
    @*<DataAnnotationsValidator />*@
    <ObjectGraphDataAnnotationsValidator/>
    <p>
        <label for="name">Enter name: </label>
        <InputText id="name" @bind-Value="customer.Name" /><br />
        <ValidationMessage For="@(() => customer.Name)" />
    </p>
    @foreach (var phone in customer.phones)
    {
<p>
    <label>Enter phone: </label>
    <InputText @bind-Value="phone.PhoneNumber" />
    <ValidationMessage For="@(() => phone.PhoneNumber)" />
</p>
    }

    <p>
        <button type="submit">submit</button>
    </p>

</EditForm>

<div>
    <p>Edit  customer</p>

    <p>@customer.Name</p>
    @foreach (var phone in customer.phones)
    {
        <p>@phone.PhoneNumber</p>

    }

</div>
<div>
     <p>Is model validated: @validated.ToString()</p>
 </div>
@code {
    EditContext EditContext;
    Customer customer;
    bool validated;

    protected override void OnInitialized()
    {
        customer = new Customer();
        EditContext = new EditContext(customer);

    }
    private void OnSubmitHandler()
    {            
        validated = EditContext.Validate();
    }

    public class Customer
    {
        [Required]
        public string Name { get; set; }  
        [ValidateComplexType]
        public List<Phone> phones { get; set; } = new List<Phone>() { new Phone { }, new Phone { }, new Phone { }};
         
    }

    public class Phone
    {
        [Required]
        public string PhoneNumber { get; set; }
    }

}
 

Комментарии:

1. Спасибо за ответ. Однако проблема, с которой я сталкиваюсь, заключается в том, что я хочу достичь следующих двух целей одновременно: 1. Привязка к списку 2. Заставить EditContext.Validate() работать. Я попробовал ваше предложение о создании класса-оболочки, а затем включить список MyClass в оболочку в качестве свойства, но аннотация данных перестает работать после того, как я это сделаю. Возможно, мне следует лучше сформулировать свои вопросы, например «Как заставить EditContext.Validate() работать при привязке EditForm к массиву».

2. Смотрите Раздел Обновления в моем ответе. Не могли бы вы пометить его как ответ, если он решил вашу проблему, чтобы другие знали, что это было полезно.