在blazor razor页面中使用editform时如何重置自定义验证错误

时间:2020-03-29 16:26:55

标签: validation razor blazor blazor-server-side

我有一个使用editcontext的editform:

    <EditForm OnValidSubmit="HandleValidSubmit" EditContext="_editContext" Context="auth">
      <DataAnnotationsValidator />
      <input type="time" @bind-value="_foodTruck.EndDelivery" @onkeydown="@(q=>ResetValidation("EndDelivery"))" >
        <ValidationMessage For="() => _foodTruck.EndDelivery" />
      <input type="time" @bind-value="_foodTruck.StartDelivery" @onkeydown="@(q=>ResetValidation("StartDelivery"))" >
        <ValidationMessage For="() => _foodTruck.StartDelivery" />
      <input class="btn btn-default" type="submit" value="save" />
    </EditForm>

我在HandleValidSubmit中进行了一些自定义验证:

EditContext _editContext = new EditContext(_foodTruck);
private async void HandleValidSubmit()
{
  var messageStore = new ValidationMessageStore(_editContext);
  if (_foodTruck.StartDelivery >= _foodTruck.EndDelivery)
  {
    messageStore.Add(_editContext.Field("EndDelivery"), "Bad time entered");
    _editContext.NotifyValidationStateChanged();
  }
 if (!_editContext.Validate()) return;
}

现在发生的是,我的自定义错误(“输入错误时间”)显示在正确的位置。唯一的问题是:更改值后该错误不会消失。因此,如果我单击“提交”按钮,就永远不会再次调用HandleValidSubmit。

我还尝试在修改字段时清空验证错误:

   protected void ResetValidation(string field)
    {
        var messageStore = new ValidationMessageStore(_editContext);        
        messageStore.Clear(_editContext.Field(field));
        messageStore.Clear();
        _editContext.NotifyValidationStateChanged();
    }

这由onkeydown调用。但这似乎也不起作用。错误消息不会消失,因此HandleValidSubmit也不会被调用。

5 个答案:

答案 0 :(得分:4)

我通过在Validation-reset上创建一个新的EditContext解决了这一问题。所以我只是将以下行添加到ResetValidation-Method中:

  _editContext = new EditContext(_foodTruck);

但是说实话:那感觉不对。因此,我将保持开放状态,以便更好地回答(希望如此)。

答案 1 :(得分:1)

我有同样的问题。我找不到简单的解决方案。类似于下面的解决方法对我有用。

按如下所示修改EditForm-

<EditForm EditContext="_editContext" OnSubmit="HandleSubmit">

@代码块

EditContext _editContext;

ValidationMessageStore msgStore;

FoodTruck _foodTruck= new FoodTruck();

protected override void OnInitialized()
{
    _editContext = new EditContext(_foodTruck);
    msgStore = new ValidationMessageStore(_editContext);
}

void HandleSubmit()
{
    msgStore.Clear();
    if(_editContext.Validate()) // <-- Model Validation
    {
        if (_foodTruck.StartDelivery >= _foodTruck.EndDelivery) //<--Custom validation
        {
            msgStore = new ValidationMessageStore(_editContext);
            msgStore.Add(_editContext.Field("EndDelivery"), "Bad time entered");
        }
    }
}

答案 2 :(得分:0)

在事件操作的末尾添加this.StateHasChanged(),以便它可以再次呈现ui元素并删除验证消息。

EditContext _editContext = new EditContext(_foodTruck);
private async void HandleValidSubmit()
{
  var messageStore = new ValidationMessageStore(_editContext);
  if (_foodTruck.StartDelivery >= _foodTruck.EndDelivery)
  {
    messageStore.Add(_editContext.Field("EndDelivery"), "Bad time entered");
    _editContext.NotifyValidationStateChanged();
     this.StateHasChanged(); //this line
  }
 if (!_editContext.Validate()) return;
}

对于另一个

protected void ResetValidation(string field)
{
        var messageStore = new ValidationMessageStore(_editContext);        
        messageStore.Clear(_editContext.Field(field));
        messageStore.Clear();
        _editContext.NotifyValidationStateChanged();
        this.StateHasChanged(); //this line
}

请让我知道它是否有效

答案 3 :(得分:0)

我遇到了与原始海报相同的问题,因此我决定在EditContext的源代码中四处浏览(谢谢source.dot.net!)。因此,我提出了一个解决方法,该解决方法足以满足Blazor团队在将来的版本中正确解决该问题的要求。

/// <summary>
/// Contains extension methods for working with the <see cref="EditForm"/> class.
/// </summary>
public static class EditFormExtensions
{
    /// <summary>
    /// Clears all validation messages from the <see cref="EditContext"/> of the given <see cref="EditForm"/>.
    /// </summary>
    /// <param name="editForm">The <see cref="EditForm"/> to use.</param>
    /// <param name="revalidate">
    /// Specifies whether the <see cref="EditContext"/> of the given <see cref="EditForm"/> should revalidate after all validation messages have been cleared.
    /// </param>
    /// <param name="markAsUnmodified">
    /// Specifies whether the <see cref="EditContext"/> of the given <see cref="EditForm"/> should be marked as unmodified.
    /// This will affect the assignment of css classes to a form's input controls in Blazor.
    /// </param>
    /// <remarks>
    /// This extension method should be on EditContext, but EditForm is being used until the fix for issue
    /// <see href="https://github.com/dotnet/aspnetcore/issues/12238"/> is officially released.
    /// </remarks>
    public static void ClearValidationMessages(this EditForm editForm, bool revalidate = false, bool markAsUnmodified = false)
    {
        var bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

        object GetInstanceField(Type type, object instance, string fieldName)
        {                
            var fieldInfo = type.GetField(fieldName, bindingFlags);
            return fieldInfo.GetValue(instance);
        }

        var editContext = editForm.EditContext == null
            ? GetInstanceField(typeof(EditForm), editForm, "_fixedEditContext") as EditContext
            : editForm.EditContext;

        var fieldStates = GetInstanceField(typeof(EditContext), editContext, "_fieldStates");
        var clearMethodInfo = typeof(HashSet<ValidationMessageStore>).GetMethod("Clear", bindingFlags);

        foreach (DictionaryEntry kv in (IDictionary)fieldStates)
        {
            var messageStores = GetInstanceField(kv.Value.GetType(), kv.Value, "_validationMessageStores");
            clearMethodInfo.Invoke(messageStores, null);
        }

        if (markAsUnmodified)
            editContext.MarkAsUnmodified();

        if (revalidate)
            editContext.Validate();
    }
}

答案 4 :(得分:0)

遇到了同样的问题,使用EditContext.Validate()以一种不太hacky的方式解决了该问题:

我已经实现了一种名为EditContext_OnFieldChanged(object sender, FieldChangedEventArgs e)的方法,该方法会在使用EditForm使用的模型的参数后立即被调用。它是这样实现的:

protected override void OnInitialized()
{
    EditContext = new EditContext(ModelExample);
    EditContext.OnFieldChanged += EditContext_OnFieldChanged;
}

这里是方法:

private void EditContext_OnFieldChanged(object sender, FieldChangedEventArgs e)
{
    EditContext.Validate();
    
    // ...
    // other stuff you want to be done when the model changes
}

EditContext.Validate()似乎会更新所有验证消息,甚至是自定义消息。