Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVVM - Validation

We're trying to figure out validation in the mvvm doing validation in the business logic or model. I've implemented the validate by exception type in our business logic - a simplified diagram can be found here: alt text

If we've got lot's of inputs that are independent of each other, there is no problem, the exception is thrown, the textbox catches it an marks it's borders red for each wrong input. However, when we've got dependent values we're in trouble. e.g.

  • Value1 and Value2 in the model must not be the same, so we've got a validate function in each of those looking for the equals value and throw an exception if that happens

  • now, if we set Value1 to 0 and Value2 to 1 everything is fine

  • Value1 gets set in the GUI to 1 --> this one gets marked red, because the validation of the other values is not triggered, so Value2 in the GUI is not marked faulty

  • Value2 gets set to 2 in the GUI, now we've reached a valid state, but only Value2 gets validated, so Value1 still is marked as faulty

Is there a common pattern to solve that issue? we don't want to introduce a dependency in the GUI between the two textboxes, because this logic should only be present in the business logic layer.

Instead of implementing the validate by exception one could also implement the IDataErrorInfo interface, but the problem still exists, there is no way to force depending values to validate their values again, at least none that i can see :)

Any help is appreciated

cheers, manni


[cleanup, removed unecessary step]


15.11.2010 - Part2

ok, big rethought here, we're going with the businesslogic tier. here is our current planned configuration: alt text ( the image is a bit small scaled here, please open it on a separate window to show it in full size) everything is more or less clear, except how to notify all the viewmodels/model clones of the different editors if the data-model under the business logic gets changed. one way to do it is to track the cloned models in the business logic which creates them. When the data-model is changed using the business logic commit(), all the other registered model clones can be notified of the changes and propagate them further. alternatively the business logic could post an event to which all the viewmodels subscribe so that they get the changes as well - could anyone give me a hint what's better?

Thanks again for the help, sorry i'm so mind-blocked ;)

like image 696
manni Avatar asked Nov 11 '10 07:11

manni


People also ask

How do you validate fields in MVVM?

Adding Validation It's a good practice for putting the validation support in a common base class that you can then inherit from different scenarios. The base class will support INotifyDataErrorInfo so that that validation gets triggered when properties change. Create add a new class called ValidatableBindableBase.

What is WPF data validation?

Syncfusion WPF input controls allow you to validate user input and display hints if validation fails. If the user input is invalid, a default red border will be shown around the UIElement.

What is frontend validation?

Client-side validation exists on the front-end and is part of the front-end secure coding requirements. It responds faster to the user's input and reduces the latency that would exist if one only used server-side data validation.

What is validation in Visual Studio?

Applies to: Visual Studio Visual Studio for Mac Visual Studio Code. Validating entity classes is the process of confirming that the values entered into data objects comply with the constraints in an object's schema, and also to the rules established for the application.


1 Answers

You could consider using the System.ComponentModel.IDataErrorInfo interface. This very handy interface gives you the ability to:

  • do validation in a MVVM compliant manner
  • do custom validation for any particular field (the validation could check several values if you want it to)
  • bind your UI to the validation errors

You implement IDataErrorInfo on your viewmodel (or even virtually in your view model base, and override it in your derived view models). Due to the nature of databinding, the values i need to check are all there in the view model, and i can test any combination of them. Of course you still have your validation in your business layer, but you no longer need to make a trip to your business layer (or Model) just to effect some validation.

Here is a quick example from a (WPF) screen that gathers some user details and does basic validation on them:

C# code:

    #region IDataErrorInfo Members

    /// <summary>
    /// Gets an error message indicating what is wrong with this object.
    /// </summary>
    /// <value></value>
    /// <returns>An error message indicating what is wrong with this object. The default is an empty string ("").</returns>
    public override string Error
    {
        get
        {
            return this["UserCode"] + this["UserName"] + this["Password"] + this["ConfirmedPassword"] + this["EmailAddress"];
        }
    }

    /// <summary>
    /// Gets the <see cref="System.String"/> with the specified column name.
    /// </summary>
    /// <value></value>
    public override string this[string columnName]
    {
        get
        {
            switch (columnName)
            {
                case "UserCode":
                    if (!string.IsNullOrEmpty(UserCode) && UserCode.Length > 20)
                        return "User Code must be less than or equal to 20 characters";
                    break;

                case "UserName":
                    if (!string.IsNullOrEmpty(UserCode) && UserCode.Length > 60)
                        return "User Name must be less than or equal to 60 characters";
                    break;

                case "Password":
                    if (!string.IsNullOrEmpty(Password) && Password.Length > 60)
                        return "Password must be less than or equal to 60 characters";
                    break;

                case "ConfirmedPassword":
                    if (Password != ConfirmedPassword)
                        return Properties.Resources.ErrorMessage_Password_ConfirmedPasswordDoesntMatch; 
                    break;

                case "EmailAddress":
                    if (!string.IsNullOrEmpty(EmailAddress))
                    {
                        var r = new Regex(_emailRegex);
                        if (!r.IsMatch(EmailAddress))
                            return Properties.Resources.ErrorMessage_Email_InvalidEmailFormat;
                    }
                    break;
            }
            return string.Empty;
        }
    }

    #endregion

and here is the XAML markup for two of the textboxes on the page (note particularly the ValidatesOnDataErrors and ValidatesOnExceptions properties in the Text binding):

<TextBox Name="UserCodeTextBox" 
         Text="{Binding UserCode, 
                Mode=TwoWay, 
                UpdateSourceTrigger=PropertyChanged, 
                ValidatesOnDataErrors=True, 
                ValidatesOnExceptions=True, 
                NotifyOnSourceUpdated=True, 
                NotifyOnTargetUpdated=True}" 
         GotFocus="Input_GotFocus"
         VerticalAlignment="Top"
         Margin="165,0,150,0"  
         CharacterCasing="Upper"
         />

<TextBox Name="UserNameTextBox" 
         Text="{Binding UserName, 
                Mode=TwoWay, 
                UpdateSourceTrigger=PropertyChanged, 
                ValidatesOnDataErrors=True, 
                ValidatesOnExceptions=True, 
                NotifyOnSourceUpdated=True, 
                NotifyOnTargetUpdated=True}" 
         GotFocus="Input_GotFocus"
         VerticalAlignment="Top"
         Margin="165,30,0,0"  
         />
like image 112
slugster Avatar answered Sep 16 '22 14:09

slugster