目錄:
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方法是我們要驗證的規則。
