2

I'm having issues getting a validation error shown when an async validation is used.

I'm using a DevExpress Textbox and via the validate method I'm using an async call to validate if a number is unique. The other local checks show validation errors fin, but when I get to the third step (async) it doesn't show the error.

I'm sure it is due to the async nature of the call. I've tried using async/await, Task.Runin so many combinations that I lost count, but still cant make it work.

The xaml:

<dxe:TextEdit
  EditValue="{Binding Mode=TwoWay, NotifyOnSourceUpdated=True, Path=Dto.Number, updateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
  InvalidValueBehavior="AllowLeaveEditor"
  IsEnabled="{Binding IsNew, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"
  NullText="Enter number"
  ValidateOnTextInput="True"
  Validate="NumberOnValidate" />

The xaml.cs

private void NumberOnValidate(object sender, ValidationEventArgs e)
{
  if (!((TextEdit) sender).IsEnabled)
  {
    return;
  }

  //Task.Run(async () => {
  e.ErrorContent = RequiredValidationRule.GetErrorMessage("Number", e.Value);

  if (string.IsNullOrWhiteSpace(e.ErrorContent?.ToString()))
  {
    e.ErrorContent = StringMaxlengthValidationRule.GetErrorMessage("Number", 255, e.Value);

    if (string.IsNullOrWhiteSpace(e.ErrorContent?.ToString()))
    {
      var dataContext = (UpsertViewModel) DataContext;
      Task.Run(async () =>
      {
        e.ErrorContent = await Validation.IsNumberUnique(dataContext.HubConnection, dataContext.SelectedType, e.Value);
      });
    }
  }

  if (!string.IsNullOrWhiteSpace(e.ErrorContent?.ToString()))
  {
    e.IsValid = false;
  }

  //});
}

The validation:

public static async Task<string> IsNumberUnique(IHubConnection hubConnection, EnumType type, object fieldValue)
{
  if (fieldValue == null || string.IsNullOrWhiteSpace(fieldValue.ToString()))
  {
    return "Cannot validate the uniqueness of the number field because it is empty.";
  }

  //Task.Run(async () =>
  //{
    try
    {
      var response = false;

      switch (type)
      {
        case EnumType.T1:
          response = await hubConnection.T1IsNumberUnique(fieldValue.ToString());

          break;

        case EnumType.T2:
          response = await hubConnection.T2IsNumberUnique(fieldValue.ToString());

          break;

        case EnumType.T3:
          response = await hubConnection.T3IsNumberUnique(fieldValue.ToString());

          break;
      }

      if (!response)
      {
        return "The number field must be unique.";
      }
    }
    catch (Exception ex)
    {
      return $"Error validating the number field for uniqueness. Exception: {ex}";
    }

    return string.Empty;
  //});

  //return string.Empty;
}

I think I've tried all ways I can think of, but that short delay in getting the async call makes the validation method skip the response and it doesn't register in the GUI.

When debugging I can see the async response is coming after the validation has occurred, so how can I align the threads to make the validation "wait" for the async response.

user2250152
  • 14,658
  • 4
  • 33
  • 57

1 Answers1

1
Task.Run(async () =>
{
    e.ErrorContent = await Validation.IsNumberUnique(dataContext.HubConnection, dataContext.SelectedType, e.Value);
});

This piece of code fires off the async task in another thread. Your original validation thread then immediately continues as you're experiencing.

I guess you could block on the Result of the async method, but this would negate the advantage of being async, and would lock the UI while it ran.

I suspect you'll need to do something hacky, like raise PropertyChanged again when the async method completes, which will force WPF to validate again, with some kind of flag to prevent the async call being run again.

GazTheDestroyer
  • 20,722
  • 9
  • 70
  • 103
  • I also tried with direct await/async, but the same result. Funny that with all the async being standard now there's no async validation available – Allan Michaelsen Jan 20 '21 at 13:01