Reputation: 5022
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.
Upvotes: 3
Views: 7976
Reputation: 4109
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));
}
}
}
Upvotes: 2
Reputation: 12315
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.
Upvotes: 1