You can use ViewModel validations to give users field-level feedback for rules that matter in one ViewModel or use case.
What a ViewModel validation does
A ViewModel validation is a named rule with an OCL expression and an error message. The expression must evaluate to true when the data is valid and false when the rule is broken.
Associate the validation with one or more ViewModel columns. When the rule is broken at runtime, each associated column receives a validation error. The client can then show feedback on the affected input control.
For example, a ViewModel that edits a person's email address can use this rule:
| Setting | Example value |
|---|---|
| Rule name | EmailAddressFormat
|
| OCL expression | self.EmailAddress.regExpMatch('^[a-zA-Z0-9+_.-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,3}$')
|
| Message | Enter a valid email address.
|
Associate EmailAddressFormat with the EmailAddress column. A value that does not match the expression causes that column to show the message.
Choose the right place for a rule
Use ViewModel validation for feedback that is specific to how users enter data in a particular view. Use model-level constraints for rules that must protect data regardless of which ViewModel, interface, or update path changes it.
| Requirement | Put the rule in | Example |
|---|---|---|
| The rule applies only to this editing experience or should be presented on selected fields in this view | ViewModel validation | Show Enter a valid email address. on the EmailAddress input in a person-edit ViewModel.
|
| The rule must hold for every instance of a model class | Model-level constraint; see Documentation:Data validation | A date of birth day must be greater than 0 and less than 32. |
Do not duplicate an existing model constraint expression in a ViewModel validation. Instead, make the ViewModel validation check whether the relevant named constraint is valid. This keeps the business rule in one place while allowing the ViewModel to decide which columns display the error.
When you use this approach, ensure that the constraint name is present and correctly spelled. An incorrectly specified constraint lookup evaluates as false, causing a persistent validation problem in the user interface.
Add a validation rule
- Open the ViewModel in the ViewModelEditor.
- Select Add Validation. A new row appears in the Validations list.
- Enter a descriptive Rule name. Use a name that identifies the condition, such as
DayOfBirthInRange. - Enter the OCL expression. Write the expression so that valid data returns
true. - Enter the Message that users should see when the expression returns
false. - Associate the rule with the columns that should show its feedback, as described in the next section.
You can add as many validation rules as the ViewModel needs.
Example: required value
To require a first name, create a validation such as:
| Setting | Value |
|---|---|
| Rule name | FirstNameRequired
|
| OCL expression | self.FirstName.IsEmpty
|
| Message | First name is required.
|
Use the expression appropriate to the rule semantics in your model. The key requirement is unchanged: the completed validation expression must return true when the entered data fulfills the rule.
Example: range
For a day-of-birth value, the valid range can be expressed as:
(self.DayOfBirth > 0) and (self.DayOfBirth < 32)
Use a message such as Day of birth must be between 1 and 31., then associate the rule with the DayOfBirth column.
Associate a validation with columns
A validation does not affect a control until you associate it with a ViewModel column. One rule can be associated with multiple columns. This is useful when a single condition depends on more than one entered value and all involved fields should indicate the problem.
- In the ViewModelEditor, right-click the ViewModel column.
- Select Validation rules.
- Select the validation rule to associate with that column.
- Repeat for every column that should display the same validation error.
For example, a rule that checks a relationship between two entered values can be associated with both columns, so users see the error beside each relevant input.
Understand the OCL context
The validation expression runs in the context of the main ViewModelClass. In a rooted ViewModel, self is the main model object that roots that ViewModel. You can therefore navigate its attributes and associations in the expression.
For example, if the main ViewModelClass is rooted in a person object, self.EmailAddress evaluates the email address of that person.
The available context depends on whether the ViewModel is rooted or unrooted. See Documentation:ViewModel for how ViewModel classes, roots, and self work.
Runtime behavior
When an associated rule evaluates to false, MDriven raises a standard WPF ValidationError for the associated column. The control's visual presentation is determined by client styling.
ViewModel validation provides immediate client feedback for the configured view. It does not replace model-level validation for data integrity. For a broader discussion of required fields, types, ranges, formats, and conditional rules, see Documentation:Data validation.
WPF validation appearance
The default WPF style can show a red border, an exclamation mark, and a tooltip containing the first validation error. Override the style when your application needs a different presentation.
<ControlTemplate x:Key="validationTemplate">
<DockPanel>
<Border BorderBrush="Red" BorderThickness="2" CornerRadius="4,4,4,4">
<AdornedElementPlaceholder/>
</Border>
<TextBlock Foreground="Red" VerticalAlignment="Center" FontWeight="ExtraBold" Margin="4">!</TextBlock>
</DockPanel>
</ControlTemplate>
<Style TargetType="TextBox">
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource validationTemplate}">
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="TextBox.ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
The template places the edited control in a red border and displays !. The trigger sets the TextBox tooltip to the error content supplied by the failed ViewModel validation.
