Reputation: 1811
What is the best way to do data validation. Is it a good practice to do validation in view models or should the validation be done in models? and also, what is the best way to implement numeric(decimal) text-box in WPF with MVVM. I am using MVVM Light toolkit.
Upvotes: 5
Views: 8657
Reputation: 22445
If you use IDataErrorInfo for Viewmodel validation - DO NOT FORGET the following:
if your viewmodel has properties other then typeof string and the input in your view can not be converted to the property type - then your input never reach the viewmodel and so the validation - and the user in front of the view is just thinking: "wtf why i dont see any validation error!"
Upvotes: 0
Reputation: 5442
Implement IDataError Info on the class and that will implement two properties Error and this[string columnName] you can implement the second property with your binding errors that you want
public class MainViewModel:ViewModelBase,IDataErrorInfo
{
public string Error
{
}
public string this[string columnName]
{
get
{
string msg=nulll;
switch(columnName)
{
case "MyProperty": //that will be your binding property
//choose your validation logic
if(MyProperty==0||MyProperty==null)
msg="My Property is required";
break;
}
return msg;
}
}
Also set ValidateOnError=true on the fields
Upvotes: 1
Reputation: 174329
To be able to provide meaningful messages to the user, it is best to make the properties of your ViewModel that should be bound to a TextBox of type string and implement IDataErrorInfo
on your ViewModel.
In my projects, I am using it like this. I created an interface IValidateable
(please forgive the name...) which implements IDataErrorInfo. My ViewModel implements this interface:
public interface IValidateable : IDataErrorInfo
{
ObservableCollection<Tuple<string, ValidationError>> InvalidProperties
{ get; }
bool IsValid { get; }
}
All my text boxes use the following style:
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError"
Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
</Style.Triggers>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90*" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Border BorderBrush="Red"
BorderThickness="1"
CornerRadius="2.75"
Grid.Column="0">
<AdornedElementPlaceholder Grid.Column="0" />
</Border>
<TextBlock Foreground="Red"
Grid.Column="1"
Margin="0"
FontSize="12"
VerticalAlignment="Center"
HorizontalAlignment="Left">
*
</TextBlock>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This will show a tool tip if the value entered doesn't conform to my rules.
Furthermore, I created a small validation engine which allows to assign rules to the properties of the view model and a base class that automatically validates the property value when a new value is set.
The interface members of IValidateable
are used to display a meaningful error message to the user when he tries to save an invalid object.
Upvotes: 6