-
Notifications
You must be signed in to change notification settings - Fork 0
ValidationProxy
The validation proxy is currently the most flexible but manageable way to provide validation process in your application with Forvalidate. Although it is especially designed for the best integration with WPF (MVVM/MVP), you can use it in any .Net project with data model validation requirement.
- The validation proxy maintains the process of validators instancing - prevents from multi-instancing of the same validator if it is not needed.
- With proxy you can extend your data model object with some metadata - it is used by the library itself to intercept UI validation exceptions.
- The validation proxy provides loose coupled relation between data model, viem model (presenter) and view without any additional requirements for interface implementing in these classes.
- Extensions for the validation proxy (provided by extension methods) allows developers to prepare simpler self-documented code.
This is a sample data model class - implementation for methods and properties is not provided here for simplicity. As you can see, there are no interface implementations or class inheritance needed. Thanks to loose coupling provided by the validation proxy such elements is not needed.
Public Class Task
Public Property TaskID() As Int32
Public Property CreateDate() As DateTime
Public Property AssignDate() As DateTime?
Public Property Priority() As Byte
Public Sub Save()
End ClassBelow, there is a sample validator class.
Imports Fortedo.ForValidate
Imports Fortedo.ForValidate.Conditions
Public Class TaskValidator : Inherits FvValidatorBase
Public Sub New()
AddRule("CreateDate").Ensure(Function(d As DateTime) d >= #1/1/2010#))
AddRule("AssignDate").Test(Function(t As Task) t.AssignDate Is Nothing OrElse t.AssigneDate >= t.CreateDate)
End Sub
End ClassAnd finally, there is some code using the data model and validator classes.
Imports Fortedo.ForValidate.Wpf
Public Class TaskPresenter
Private _task As Task
Public Sub New()
_task = New Task
'set proxy for a task object and associate it with the new instance of TaskValidator validator
FvProxy.Connect(Of TaskValidator)(_task)
End Sub
Public Sub ValidateAndSave()
'note that validation is made using proxy - framework will use previously associated TaskValidator instance
Dim result As ValidationResult = FvProxy.Validate(_task)
If result.IsValid Then
_task.Save
Else
MessageBox.Show("There are some errors in task properties.")
End if
End Sub
Public Sub Close()
'you should disconnect proxy for an object if you do not need it anymore
FvProxy.Disconnect(_task)
End Sub
End ClassThe WPF is a very flexible and rich framework but extensibility of the validation is really painful task. Although you could use some IDataErrorInfo interface or custom validation rules, there are still some blockers and you cannot get what you want. This is where another part of Forvalidate framework can help you - in the Fortedo.Forvalidate.Wpf namespace there is a special WPF Binding extender - it is the FvBinding class. You can use it every place where you bind object you want to be validated by Forvalidate.
- You can use
FvBindingjust like the standard one binding - as a markup extension or markup element, it is possible to use it in a code either. -
FvBindingis strictly connected with the validation proxy - the other is used to determine which validator to use for validating bound objects. - If some exception is invoked while bound property is about to be updated,
FvBindingwill propagate it to the validadation proxy so retrieved validation result would be extended to UI exceptions. - On the other hand, all the rules defined in the associated validator (and even in the nested ones) are executed after every change of the bound property. The results are transferred to the UI and can be used there (e.g. in
Validation.ErrorTemplate). -
FvBindingkeeps invalidated state of UI controls in such situations where WPF "forgets" about it.
After the longish introduction... high time for an example.
<?xml version="1.0" encoding="utf-8"?>
<UserControl x:Class="Views.DetailsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:for="http://forvalidate.fortedo.com">
<!-- There is URL Forvalidate namespace created for your convenience -->
<UserControl.Resources>
<!-- It is a little gift from Forvalidate that converts errors to more user-friendly form -->
<for:ErrorsToStringConverter x:Key="ErrorsToStringConverter"/>
<!-- We prepare Validation.ErrorTemplate for each TextBox -->
<!-- As you can see, it is possible to use FvBinding and default WPF mechanisms together -->
<Style TargetType="{x:Type TextBox}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="true">
<Border Background="Red" DockPanel.Dock="right" Margin="5,0,0,0" CornerRadius="10">
<TextBlock VerticalAlignment="center" HorizontalAlignment="Center"
FontWeight="Bold" Foreground="White">
<TextBlock.Text>
<!-- You do not need using FvBinding here - the property is not validate -->
<Binding ElementName="customAdorner"
Path="AdornedElement.(Validation.Errors)"
Converter="{StaticResource ErrorsToStringConverter}}"/>
</TextBlock.Text>
</TextBlock>
</Border>
<AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center">
<Border BorderBrush="red" BorderThickness="1" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<!-- Assume there is FvProxy connected to the Task object in data context -->
<StackPanel DataContext="{Binding Task}" Orientation="Vertical">
<!-- You simply use FvBinding instead of the standard Binding -->
<!-- Do not bother about any other things - Forvalidate will do the rest -->
<TextBox Text="{for:FvBinding CloseDate, StringFormat=yyyy-MM-dd}"/>
<TextBox Text="{for:FvBinding Case.ReceiveDate, StringFormat=yyyy-MM-dd}"/>
</StackPanel>
</Grid>
</UserControl>