目录:
1、ValidationRule 验证
ValidationRule:是通过ValidationRule中的的Validate方法来验证我们绑定的属性。所以我们的用法是继承ValidationRule,重写他的Validate方法。示例
public class RequiredRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (value == null)
return new ValidationResult(false, "不能为空值!");
if (string.IsNullOrEmpty(value.ToString()))
return new ValidationResult(false, "不能为空字符串!");
return new ValidationResult(true, null);
}
}
而XAML中需要把错误信息显示出来。
<Window.Resources>
<ControlTemplate x:Key="ErrorTemplate">
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder/>
</Border>
</ControlTemplate>
<Style TargetType="TextBox">
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ErrorTemplate}">
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<TextBlock Text="姓名"/>
<TextBox>
<TextBox.Text>
<Binding Path="Name" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
<Binding.ValidationRules>
<ValidationRules:RequiredRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<TextBlock Text="年龄"/>
<TextBox >
<TextBox.Text>
<Binding Path="Age" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
<Binding.ValidationRules>
<ValidationRules:GreaterThanRule Number="10"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</StackPanel>
这样显示的错误信息就会以 ToolTip和红色边框的形式显示出来。但这边如果又在TextBox里面设置ToolTip那么就会优先选择TextBox里的,也就是Style中的ToolTip遇到错误信息是不会显示出来的,而是显示TextBox中的ToolTip。所以我们可以改善一下显示的模版来解决这个问题。
<ControlTemplate x:Key="ErrorTemplate">
<DockPanel LastChildFill="true">
<Border Background="Red" DockPanel.Dock="right" Margin="5,0,0,0" Width="20" Height="20" CornerRadius="10"
ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
<TextBlock Text="!" VerticalAlignment="center" HorizontalAlignment="center" FontWeight="Bold" Foreground="white">
</TextBlock>
</Border>
<AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center" >
<Border BorderBrush="red" BorderThickness="1" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
2、Exception 验证
Exception :我们xaml中绑定的对象是属性。所以Exception验证,就是通过属性的改变来判断是否正常。如:
public int Age
{
get { return _age; }
set
{
if (value > 200)
{
throw new Exception("年龄不能大于200");
}
_age = value;
}
}
同样跑出的异常在Xaml中也要显示下。XAML同上。这种方式就会破坏POCO的设计原则。
3、IDataErrorInfo 验证
IDataErrorInfo:这个验证是通过我们的实体对象继承IDataErrorInfo来实现的。这里声明的this索引器来访问类的成员。
public class BaseDataErrorInfo : IDataErrorInfo
{
private string _error;
public string this[string columnName]
{
get { return GetErrorFor(columnName); }
}
public string Error
{
get { return _error; }
set { _error = value; }
}
public virtual string GetErrorFor(string columnName)
{
return string.Empty;
}
}
public class Person : BaseDataErrorInfo
{
public string Name { get; set; }
public override string GetErrorFor(string columnName)
{
if (columnName == "Name")
if (string.IsNullOrEmpty(Name))
return "Name 不能为空";
return base.GetErrorFor(columnName);
}
}
XAML同上。
4、Custom Control 验证
这里我即不想污染实体类,又想实现一个通用的Validate。我想通过我xaml绑定的属性和它所属的控件。来显示ToolTip。
public abstract class Validator : FrameworkElement
{
static Validator()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Validator), new FrameworkPropertyMetadata(typeof(Validator)));
}
public virtual string ErrorMessage { get { return string.Empty; } }
public abstract bool InitialValidation();
public FrameworkElement ElementName
{
get { return (FrameworkElement)GetValue(ElementNameProperty); }
set { SetValue(ElementNameProperty, value); }
}
// Using a DependencyProperty as the backing store for ElementName. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ElementNameProperty =
DependencyProperty.Register("ElementName", typeof(FrameworkElement), typeof(Validator), new PropertyMetadata(null));
public object Source
{
get { return (object)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
// Using a DependencyProperty as the backing store for Source. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SourceProperty =
DependencyProperty.Register("Source", typeof(object), typeof(Validator), new UIPropertyMetadata(new PropertyChangedCallback(ValidPropertyPropertyChanged)));
private static void ValidPropertyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var validator = d as Validator;
if (validator != null)
validator.SetSourceFromProperty();
if (string.IsNullOrEmpty(e.NewValue.ToString()))
{
if (validator != null)
{
validator.IsValid = validator.InitialValidation();
if (validator.ElementName.DataContext != null)
validator.ShowToolTip();
validator.IsValid = false;
}
}
}
private void ShowToolTip()
{
if (IsValid)
{
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(1.5);
_toolTip = new ToolTip();
_toolTip.StaysOpen = true;
_toolTip.PlacementTarget = ElementName;
_toolTip.Placement = PlacementMode.Right;
_toolTip.Content = ErrorMessage;
_toolTip.IsOpen = true;
timer.Tick += (sender, args) =>
{
_toolTip.IsOpen = false;
timer.Stop();
};
timer.Start();
}
}
private void SetSourceFromProperty()
{
var expression = this.GetBindingExpression(SourceProperty);
if (expression != null && this.ElementName == null)
this.SetValue(Validator.ElementNameProperty, expression.DataItem as FrameworkElement);
}
private ToolTip _toolTip;
private DispatcherTimer timer;
public bool IsValid { get; set; }
}
这是一个简单的Validate基类。提供思想。功能不完善。
然后继承这个Validator
public class RequiredValidator : Validator
{
public override string ErrorMessage { get { return "不能为空值"; } }
public override bool InitialValidation()
{
if (Source == null)
return false;
return string.IsNullOrEmpty(Source.ToString());
}
}
这里ErrorMessage是显示错误信息。
InitialValidation方法是我们要验证的规则。