I have a application with multiply ViewModels. Some property have DataAnnotations.
[Required(ErrorMessage = "Field 'Range' is required.")]
[Range(1, 10, ErrorMessage = "Field 'Range' is out of range.")]
public int Password
{
get
{
return _password;
}
set
{
if (_password != value)
{
_password = value;
RaisePropertyChanged("Password");
}
}
}
How validation can be done by implementing the IDataErrorInfo or INotifyDataErrorInfo interface for all viewmodels?
I use This article, but validate when propertychange and don't validate required field.
Here is a simple example which uses IDataErrorInfo. This should help you get started.
XAML:
<Grid>
<Grid.Resources>
<ControlTemplate x:Key="LeftErrorTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding AdornedElement.(Validation.Errors).[0].ErrorContent, ElementName=ErrorAdorner}" Background="Red" Foreground="White" FontWeight="Bold" VerticalAlignment="Center"/>
<AdornedElementPlaceholder x:Name="ErrorAdorner">
<Border BorderBrush="Red" BorderThickness="1" />
</AdornedElementPlaceholder>
</StackPanel>
</ControlTemplate>
</Grid.Resources>
<TextBlock Height="23" HorizontalAlignment="Left" Margin="158,66,0,0" Name="textBlock1" Text="Name" VerticalAlignment="Top" Width="44" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="217,65,0,0" Name="textBox1" VerticalAlignment="Top" Width="120"
Text="{Binding Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
Validation.ErrorTemplate="{StaticResource LeftErrorTemplate}"/>
</Grid>
Code behind:
using System;
using System.Windows;
using System.ComponentModel;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var vm = new ViewModel();
this.DataContext = vm;
}
}
public class ViewModel : ObservableBase, IDataErrorInfo
{
private string _Name;
public string Name
{
get { return _Name; }
set
{
_Name = value;
OnPropertyChanged("Name");
}
}
public string Error
{
get { throw new NotImplementedException(); }
}
public string this[string columnName]
{
get
{
string errorMessage = string.Empty;
switch (columnName)
{
case "Name":
if (string.IsNullOrEmpty(Name))
errorMessage = "Enter name";
else if (Name.Trim() == string.Empty)
errorMessage = "Enter valid name";
break;
}
return errorMessage;
}
}
}
public class ObservableBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Hi you will have to create some method that Validates the annotations Like ValidateMethod in my code
public class ViewModel:INotifyPropertyChanged,IDataErrorInfo
{
int _password;
[Required(ErrorMessage = "Field 'Range' is required.")]
[Range(1, 10, ErrorMessage = "Field 'Range' is out of range.")]
public int Password
{
get
{
return _password;
}
set
{
if (_password != value)
{
_password = value;
Validate("Password", value);
Notify("Password");
}
}
}
private void Validate(string propertyName, object value)
{
if (string.IsNullOrEmpty(propertyName))
throw new ArgumentNullException("propertyName");
string error = string.Empty;
var results = new List<System.ComponentModel.DataAnnotations.ValidationResult>(2);
bool result = Validator.TryValidateProperty(
value,
new ValidationContext(this, null, null)
{
MemberName = propertyName
},
results);
if (!result && (value == null || ((value is int || value is long) && (int)value == 0) || (value is decimal && (decimal)value == 0)))
return;
if (!result)
{
System.ComponentModel.DataAnnotations.ValidationResult validationResult = results.First();
if (!errorMessages.ContainsKey(propertyName))
errorMessages.Add(propertyName, validationResult.ErrorMessage);
}
else if (errorMessages.ContainsKey(propertyName))
errorMessages.Remove(propertyName);
}
#region INotifyPropertyChanged
public void Notify(string propName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
#region IDataErrorInfo
public string Error
{
get { throw new NotImplementedException(); }
}
private Dictionary<string, string> errorMessages = new Dictionary<string, string>();
public string this[string columnName]
{
get
{
if(errorMessages.ContainsKey(columnName))
return errorMessages[columnName];
return null;
}
}
#endregion
}
>xaml
<TextBox Text="{Binding Password, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" Height="70" Width="200" />
xaml.cs
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
You need to call the Validate method from setter of the property which applies DataAnnotations and make sure call it before Notifying the PropertyChanged.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With