Closed guswct closed 5 years ago
This is a known problem in the current version of Blazor.
I'll see if there is anything I can do
Thank you! That would be awesome
Do this in your form
<EditForm Model=Person OnSubmit=FormSubmitted>
</EditForm>
@code {
Person Person = new Person();
void FormSubmitted(EditContext editContext)
{
bool formIsValid = editContext.ValidateWholeForm();
System.Diagnostics.Debug.WriteLine($"Form is valid: {formIsValid}");
}
}
And here is a helper class to fix the Blazor bug.
using Microsoft.AspNetCore.Components.Forms;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace HandlingFormSubmission
{
public static class EditContextExtensions
{
static PropertyInfo IsModifiedProperty;
static MethodInfo GetFieldStateMethod;
public static bool ValidateWholeForm(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 (instance.GetType().Assembly == typeof(string).Assembly)
return;
if (validatedObjects.Contains(instance))
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);
}
}
}
This worked like a charm, thanks a lot ;-)
You are welcome :)
I've added the following Extension
<EditForm Model=Person OnSubmit=FormSubmitted>
</EditForm>
void FormSubmitted(EditContext editContext)
{
bool isValid = editContext.ValidateWholeForm();
}
This will validate the EditForm.Model and all its properties (recursively).
Thanks for this great tool. In the example projects, when I click submit, the addresses don't show any validation errors, am I missing something? Thanks