一、概述
我們知道,Binding好比架設在Source和Target之間的橋梁,數據可以借助這個橋梁進行流通。在數據流通的過程中,我們可以在Binding這座橋梁上設置關卡,對數據的有效性進行驗證。
二、驗證方法
我們利用Binding的ValidationRules(類型為Collection<ValidationRule)對數據進行驗證。從它的名稱和類型可以得知,我們可以為每個Binding設置多個數據校驗條件,每個條件是一個
ValidationRule對象,ValidationRule類是個抽象類,使用的時候,我們需要創建它的派生類並實現它的Validate方法。
Validate方法返回值是ValidationResult類型對象,如果校驗通過,需要把ValidationResult對象的IsValid屬性設置為true,反之,設置false並為其ErrorContent屬性設置一個合適的消息內容,一般情況下是一個字符串。
三、例子
Demo1
假設UI上有一個Slider和一個TextBox,我們以Slider為源,TextBox為Target,Slider的取值范圍為0~100,也就是說我們要需要校驗TextBox中輸入的值是不是在1~100這個范圍內。

1 using System.Globalization; 2 using System.Windows; 3 using System.Windows.Controls; 4 5 namespace BindingDemo4ValidationRule 6 { 7 /// <summary> 8 /// Interaction logic for MainWindow.xaml 9 /// </summary> 10 public partial class MainWindow : Window 11 { 12 public MainWindow() 13 { 14 InitializeComponent(); 15 } 16 } 17 public class RangeValidationRule:ValidationRule 18 { 19 public override ValidationResult Validate(object value, CultureInfo cultureInfo) 20 { 21 double myValue = 0; 22 if(double.TryParse(value.ToString(),out myValue)) 23 { 24 if (myValue >= 0 && myValue <= 100) 25 { 26 return new ValidationResult(true, null); 27 } 28 } 29 return new ValidationResult(false, "Input should between 0 and 100"); 30 } 31 } 32 }

1 <Window x:Class="BindingDemo4ValidationRule.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:BindingDemo4ValidationRule" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="350" Width="525"> 9 <Grid> 10 <Slider Margin="10,120,-10,-120" Minimum="0" Maximum="100" Name="slider" Value="10"></Slider> 11 <TextBox Height="50" Margin="5,30,5,240" > 12 <TextBox.Text> 13 <Binding ElementName="slider" Path="Value" UpdateSourceTrigger="PropertyChanged"> 14 <Binding.ValidationRules> 15 <local:RangeValidationRule/> 16 </Binding.ValidationRules> 17 </Binding> 18 </TextBox.Text> 19 </TextBox> 20 21 </Grid> 22 </Window>
運行結果如下:
從結果中可以看出,當我們在TextBox中輸入的值不在0~100的范圍內的時候,TextBox會顯示紅色邊框,提示值是錯誤的。
Demo2
默認情況下,Binding校驗默認來自Source的數據總是正確的,只有來自Target的數據(Target多為UI控件,等價於用戶的輸入)才有可能出現問題,為了不讓有問題的數據污染Source,所以需要校驗。換句話說,Binding只在Target被外部更新時候進行校驗,而來自Binding的Source數據更新Target時是不會進行校驗的。
當來自Source的數據也有可能出現問題的時候,我們需要將校驗條件的ValidatesOnTargetUpdated屬性設置為true。
我們把Xaml代碼改為以下的時候,會發現當移動滑動條在0以下或者100以上的時候,TextBox邊框也會變成紅色。
1 <Window x:Class="BindingDemo4ValidationRule.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:BindingDemo4ValidationRule" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="350" Width="525"> 9 <Grid> 10 <Slider Margin="10,120,10,-120" Minimum="-10" Maximum="110" Name="slider" Value="10"></Slider> 11 <TextBox Height="50" Margin="5,30,5,240" > 12 <TextBox.Text> 13 <Binding ElementName="slider" Path="Value" UpdateSourceTrigger="PropertyChanged"> 14 <Binding.ValidationRules> 15 <local:RangeValidationRule ValidatesOnTargetUpdated="True"/> 16 </Binding.ValidationRules> 17 </Binding> 18 </TextBox.Text> 19 </TextBox> 20 21 </Grid> 22 </Window>
Demo3
當校驗發生錯誤的時候,Validate方法返回的ValidationResult對象會攜帶一條錯誤消息,下面我們就要顯示這個錯誤消息。
為了達到這個目的,我們需要把Binding的NotifyOnValidationError屬性設置為true,這樣當數據校驗失敗的時候,Binding會像報警一樣發出一個信號,這個信號會以Binding對象的Target為起點在UI樹上傳播,如果某個節點上設置了對這種信號的偵聽器,那么這個偵聽器就會觸發來處理這個信號。詳細參加以下代碼:

1 using System.Globalization; 2 using System.Windows; 3 using System.Windows.Controls; 4 5 namespace BindingDemo4ValidationRule 6 { 7 /// <summary> 8 /// Interaction logic for MainWindow.xaml 9 /// </summary> 10 public partial class MainWindow : Window 11 { 12 public string TipMessage 13 { 14 get { return (string)GetValue(TipMessageProperty); } 15 set { SetValue(TipMessageProperty, value); } 16 } 17 18 // Using a DependencyProperty as the backing store for TipMessage. This enables animation, styling, binding, etc... 19 public static readonly DependencyProperty TipMessageProperty = 20 DependencyProperty.Register("TipMessage", typeof(string), typeof(MainWindow), new PropertyMetadata("Tip")); 21 22 public MainWindow() 23 { 24 InitializeComponent(); 25 this.DataContext = this; 26 } 27 28 private void tbx1_Error(object sender, ValidationErrorEventArgs e) 29 { 30 if (Validation.GetErrors(tbx1).Count > 0) 31 { 32 TipMessage = Validation.GetErrors(tbx1)[0].ErrorContent.ToString(); 33 } 34 else 35 { 36 TipMessage = ""; 37 } 38 } 39 } 40 public class RangeValidationRule : ValidationRule 41 { 42 public override ValidationResult Validate(object value, CultureInfo cultureInfo) 43 { 44 double myValue = 0; 45 if (double.TryParse(value.ToString(), out myValue)) 46 { 47 if (myValue >= 0 && myValue <= 100) 48 { 49 return new ValidationResult(true, null); 50 } 51 } 52 53 return new ValidationResult(false, "Input should between 0 and 100"); 54 } 55 } 56 }

1 <Window x:Class="BindingDemo4ValidationRule.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:BindingDemo4ValidationRule" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="350" Width="525"> 9 <Grid> 10 <Slider Margin="10,120,10,-120" Minimum="-10" Maximum="110" Name="slider" Value="10"></Slider> 11 <TextBox Height="50" Margin="5,30,5,240" Name="tbx1" Validation.Error="tbx1_Error"> 12 <TextBox.Text> 13 <Binding ElementName="slider" Path="Value" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True"> 14 <Binding.ValidationRules> 15 <local:RangeValidationRule ValidatesOnTargetUpdated="True"/> 16 </Binding.ValidationRules> 17 </Binding> 18 </TextBox.Text> 19 </TextBox> 20 <Label Height="50" Margin="5,154,-5,116" Content="{Binding TipMessage}" Foreground="Red"> 21 22 </Label> 23 24 </Grid> 25 </Window>
運行結果以下: