enisn / UraniumUI

Uranium is a Free & Open-Source UI Kit for MAUI.
Apache License 2.0
1.19k stars 142 forks source link

Is there a way to use validations independent of FormView? #607

Open JajaHarris opened 8 months ago

JajaHarris commented 8 months ago

I have a page that uses a reusable header component and the submit button is part of that component. The form fields are siblings to the header component. Because the submit button is embedded within the header component I can't mark it as "IsSubmitButton". So I'm trying to figure out whats the best approach for this scenario.

Can I skip wrapping the TextFields within a FormView and still use the various validation tags on my TextFields and trigger the validation check from my ViewModel?

enisn commented 8 months ago

Here is my thought: 👉 https://github.com/enisn/UraniumUI/issues/608#issuecomment-1993988716

DevFromDownUnder commented 8 months ago

I already do this

The main thing is that the view model will not trigger revalidation in the view

I use the below (might need to update slighly if you will be changing the binding context a lot)

My views also inherit from ObservableValidator, which have a ErrorsChanged event and I call this to validate before executing logic.

In view model

ValidateAllProperties();

if (HasErrors)
{
    return;
}

In view (ContentPageBase, custom class for me)

#region ViewModel Error Validation Handling

//Allows the view model to pass back validations as they are not done automatically

protected override void OnBindingContextChanged()
{
    base.OnBindingContextChanged();

    if (BindingContext is ObservableValidator viewModel)
    {
        viewModel.ErrorsChanged += ViewModel_ErrorsChanged;
    }
}

private void ViewModel_ErrorsChanged(object? sender, System.ComponentModel.DataErrorsChangedEventArgs e)
{
    ValidateChildren(this.Content);
}

private void ValidateChildren(IView view)
{
    if (view is Layout layout)
    {
        foreach (IView item in layout.Children)
        {
            if (item is IValidatable validation)
            {
                //Need to fire view changes on UI thread
                Dispatcher.Dispatch(validation.DisplayValidation);
            }
            else
            {
                ValidateChildren(item);
            }
        }
    }
}

#endregion ViewModel Error Validation Handling