WPF绑定

来源:互联网 发布:在线监测数据造假刑法 编辑:程序博客网 时间:2024/06/01 10:38

 Binding类,主要是用于数据绑定,它包含了一系列可用的属性、方法,已经使用过的总结如下:

1、Source:数据来源对象,可以是自定义的类或者是控件

2、ElementName:数据来源控件名称

3、Path:数据绑定路径,用于数据绑定的属性需要是依赖属性,或者完成自动更新机制的属性【通过实现INotifyPropertyChanged】

 

其实对于这个类还有别的属性和方法,总结如下:

 

第一部分、转换器【实现接口:IValueConverter】

 

转换器实际上就是对于绑定的属性的值进行转换,它可以用在这样的场景:

数据库对于性别存储的是一个1、0值,所以绑定到相关的控件时候要根据性别显示不同的文字“男”、“女”,所以要做一个转换,可以这样做:

A、在sql语句中完成

B、使用诸如:sex == 1 ?“男”:“女”这样的表达式

C、使用数据绑定转换器

 

1、要使用转换器的话,需要自定义一个继承并实现了IValueConverter的类,其具体代码如下:

[c-sharp] view plaincopy
  1. public class CustomizeConverter : IValueConverter  
  2. {  
  3.     #region IValueConverter 成员  
  4.   
  5.     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)  
  6.     {  
  7.         //if (targetType != typeof(Int32))  
  8.         //{  
  9.         //    throw new Exception("输入的数据类型必须是Int32类型的数据");  
  10.         //}  
  11.   
  12.         if (parameter != null)  
  13.         {  
  14.             return (int.Parse(parameter.ToString()) == 1 ? "男" : "女");  
  15.         }  
  16.   
  17.         return (int.Parse(value.ToString()) == 1 ? "男" : "女");  
  18.     }  
  19.   
  20.     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)  
  21.     {  
  22.         throw new NotImplementedException();  
  23.     }  
  24.  
  25.     #endregion  
  26. }  

 

2、XAML代码如下:

[xhtml] view plaincopy
  1. <Window x:Class="WpfApplication1.Window6"  
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
  4.     xmlns:location="clr-namespace:WpfApplication1"       
  5.     Title="Window6" Height="300" Width="300">  
  6.     <Window.Resources>  
  7.         <location:CustomizeConverter x:Key="cConverter"></location:CustomizeConverter>  
  8.         <location:ObjForBindOnConverter x:Key="objForBind" Name="Alice">  </location:ObjForBindOnConverter>  
  9.     </Window.Resources>  
  10.     <Grid DataContext="{Binding Source={StaticResource objForBind}}">  
  11.         <Grid.ColumnDefinitions>  
  12.             <ColumnDefinition Width="50"/>  
  13.             <ColumnDefinition/>  
  14.         </Grid.ColumnDefinitions>  
  15.         <Grid.RowDefinitions>  
  16.             <RowDefinition Height="30"/>  
  17.             <RowDefinition Height="30"/>  
  18.         </Grid.RowDefinitions>  
  19.           
  20.         <Label Content="姓名:" Grid.Column="0" Grid.Row="0"></Label>  
  21.         <Label Content="性别:" Grid.Column="0" Grid.Row="1"></Label>  
  22.           
  23.         <Label Content="{Binding Path=Name}" Grid.Column="1" Grid.Row="0"></Label>  
  24.         <Label Content="{Binding Path=Sex,Converter={StaticResource cConverter}}" Grid.Column="1" Grid.Row="1"></Label>  
  25.     </Grid>  
  26. </Window>  

 

3、结果如下:

 

从流程上看,转换器是在数据绑定之后进行的,可以看到在自定义的转换类CustomizeConverter的函数Convert中有几行被注释的代码,如果在这个例子中那这几行代码放开的话,代码中定义的异常会被抛出,这是因为:

A、Label首先绑定属性Sex

B、将Label将属性Content作为函数Convert的第一个参数value传入方法,同时这个属性的类型将作为参数targetType传入

C、由于Label将属性Content得属性是Object,所以不管绑定的数据是什么,这个异常throw new Exception("输入的数据类型必须是Int32类型的数据");将一定抛出

 

另外,自定义的转换类CustomizeConverter的函数Convert中还包含了parameter参数,其类型是Object,这个参数所对应的是Binding类的ConverterParameter属性。

 

所以当我们在Label的绑定中修改成如下代码的时候,增加了【ConverterParameter=1】

[c-sharp] view plaincopy
  1. <Label Content="{Binding Path=Sex,Converter={StaticResource cConverter},  ConverterParameter=1 }" Grid.Column="1" Grid.Row="1"></Label>  

 

其他代码不变,结果会改变成如下:

 

之所以会这样,是因为在定义转换类CustomizeConverter的时候,首先判断了参数parameter,当parameter不为空的时候就根据这个参数的值作出相应的转换。

 

第二部分、数据绑定模式

之前的数据绑定,都是从数据源 -> 目标对象的绑定,也就是更新了数据源的相关属性,目标对象也会发生相应的改变。

 

但是实际上,对于Binding类而言,绑定的模式有4种,可以使用Mode属性进行设置:

A、OneWay : 当数据源改变时,目标对象会被更新。

B、TwoWay : 顾名思义,就是数据源和目标对象任意一方改变时,另一方就会改变。

C、OneWayToSource : 和A相反,当目标对象改变的时候,数据源将会改变。

D、OneTime : 只在数据源初始化的时候,绑定一次到目标对象上,之后两者没有关系。

 

因为存在了双向的绑定,所以对于何时触发类似于目标对象改变的时候通知数据源的方式,Binding也给出了三种方式,可以使用UpdateSourceTrigger属性进行设置:

A、PropertyChanged : 只要值被改变,立即触发。

B、LostFocus : 当包含值的对象失去焦点【一般是控件】的时候,立即触发。

C、Explicit: 调用BindingExpression.UpdateSource方法,来触发更新。

 

所以,根据以上内容,可以将第一部分代码更新成

1、XAML的部分:

[xhtml] view plaincopy
  1. <Window x:Class="WpfApplication1.Window6"  
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
  4.     xmlns:location="clr-namespace:WpfApplication1"       
  5.     Title="Window6" Height="300" Width="300">  
  6.     <Window.Resources>  
  7.         <location:CustomizeConverter x:Key="cConverter"></location:CustomizeConverter>  
  8.         <location:ObjForBindOnConverter x:Key="objForBind" Name="Alice"></location:ObjForBindOnConverter>  
  9.     </Window.Resources>  
  10.     <Grid DataContext="{Binding Source={StaticResource objForBind}}">  
  11.         <Grid.ColumnDefinitions>  
  12.             <ColumnDefinition Width="140"/>  
  13.             <ColumnDefinition/>  
  14.               
  15.         </Grid.ColumnDefinitions>  
  16.         <Grid.RowDefinitions>  
  17.             <RowDefinition Height="30"/>  
  18.             <RowDefinition Height="30"/>  
  19.             <RowDefinition Height="30"/>  
  20.             <RowDefinition Height="30"/>  
  21.         </Grid.RowDefinitions>  
  22.           
  23.         <Label Content="姓名:" Grid.Column="0" Grid.Row="0"></Label>  
  24.         <Label Content="性别:" Grid.Column="0" Grid.Row="1"></Label>  
  25.         <TextBox Text="{Binding Path=Name,Mode=OneWayToSource,UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Grid.Row="0"></TextBox>  
  26.         <Label Content="{Binding Path=Sex,Converter={StaticResource cConverter},ConverterParameter=1}" Grid.Column="1" Grid.Row="1"></Label>  
  27.         <Label Content="{Binding Path=Name}" Grid.Column="1" Grid.Row="2"></Label>  
  28.         <Button Content="更新数据" Grid.Column="1" Grid.Row="3" Click="Button_Click"></Button>  
  29.     </Grid>  
  30. </Window>  

这一次在Grid中增加了两行,同时将第二列第一行的Label控件更改成TextBox控件,然后在TextBox控件上指明Mode以及UpdateSourceTrigger属性的值,最后还添加了一个按钮,以及为按钮添加单击事件。

 

2、单击事件的代码:

[c-sharp] view plaincopy
  1. private void Button_Click(object sender, RoutedEventArgs e)  
  2. {  
  3.     (this.Resources["objForBind"as ObjForBindOnConverter).Name = "根据按钮更新的名字";  
  4. }  

 

3、运行结果:

A、Onload之后的结果

可以看到,TextBox和Label中的值都是空的,这是因为TextBox的绑定模式是OneWayToSource,而初始化的时候控件的Text属性是空的,所以,导致数据眼为空。

 

B、当在文本框中输入文本的结果

这个结果显示了,当文本框的文本属性被更新后,数据源也会被更新,而Label的文本来源和文本框使用的是同一个,所以这个时候Label的文本也会被改变。

 

C、当点击按钮后的结果

可以看出,TextBox的文本没有改变,正是由于其绑定模式决定的,而Label的文本改变了,因为它使用的是默认的绑定模式。

 

第三部分、验证器【ValidationRule】

转换器更多充当一个适配器的角色,而验证器就是在数据绑定之后,转换之前对数据进行验证。

 

1、可以自定义一个实现ValidationRule的验证器类,代码如下:

[c-sharp] view plaincopy
  1. public class CustomizeValidationRule : ValidationRule  
  2. {  
  3.     public override ValidationResult Validate(object value,  
  4.         System.Globalization.CultureInfo cultureInfo)  
  5.     {  
  6.         char[] valueChar = { '1''2''3''4''5''6''7''8''9''0' };  
  7.         if (value.ToString().IndexOfAny(valueChar) != -1)  
  8.         {  
  9.             return new ValidationResult(false"名称当中不可包含数字");  
  10.         }  
  11.   
  12.         return new ValidationResult(truenull);  
  13.     }  
  14. }  

 

ValidationRule是一个抽象类,只需要实现一个方法即可使用,返回的是一个ValidationResult对象,包含了验证的所有信息。

 

2、XAML的代码如下:

[xhtml] view plaincopy
  1. <Window x:Class="WpfApplication1.Window6"  
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
  4.     xmlns:location="clr-namespace:WpfApplication1"       
  5.     Title="Window6" Height="300" Width="300">  
  6.     <Window.Resources>  
  7.         <location:CustomizeConverter x:Key="cConverter"></location:CustomizeConverter>  
  8.         <location:ObjForBindOnConverter x:Key="objForBind" Name="Alice"></location:ObjForBindOnConverter>  
  9.   
  10.     </Window.Resources>  
  11.     <Grid DataContext="{Binding Source={StaticResource objForBind}}">  
  12.         <Grid.ColumnDefinitions>  
  13.             <ColumnDefinition Width="140"/>  
  14.             <ColumnDefinition/>  
  15.   
  16.         </Grid.ColumnDefinitions>  
  17.         <Grid.RowDefinitions>  
  18.             <RowDefinition Height="30"/>  
  19.             <RowDefinition Height="30"/>  
  20.             <RowDefinition Height="30"/>  
  21.             <RowDefinition Height="30"/>  
  22.         </Grid.RowDefinitions>  
  23.   
  24.         <Label Content="姓名:" Grid.Column="0" Grid.Row="0"></Label>  
  25.         <Label Content="性别:" Grid.Column="0" Grid.Row="1"></Label>  
  26.         <TextBox Grid.Column="1" Grid.Row="0" Validation.Error="TextBox_Error" x:Name="txtForName">  
  27.             <TextBox.Text>  
  28.                 <Binding Path="Name" Mode="OneWayToSource" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True">  
  29.                     <Binding.ValidationRules>  
  30.                         <location:CustomizeValidationRule>  
  31.                         </location:CustomizeValidationRule>  
  32.                     </Binding.ValidationRules>  
  33.                 </Binding>  
  34.             </TextBox.Text>  
  35.         </TextBox>  
  36.         <Label Content="{Binding Path=Sex,Converter={StaticResource cConverter},ConverterParameter=1}" Grid.Column="1" Grid.Row="1"></Label>  
  37.         <Label Content="{Binding Path=Name}" Grid.Column="1" Grid.Row="2"></Label>  
  38.         <Button Content="更新数据" Grid.Column="1" Grid.Row="3" Click="Button_Click"></Button>  
  39.     </Grid>  
  40. </Window>  

这一次修改的仍然是绑定Name属性的TextBox控件,和之前不一样的是,这一次将把Binding作为一个节点使用,而不是一个属性。

主要修改了几个部分:

A、为Binding指明了NotifyOnValidationError属性,这样当出现验证不通过的信息的时候将会触发相关事件。

B、为TextBox指明了Validation.Error事件,这个事件主要用于处理验证失败时的信息。

C、将自定义的CustomizeValidationRule绑定到Binding的ValidationRules节点中。

 

3、Validation.Error事件的代码如下:

[c-sharp] view plaincopy
  1. private void TextBox_Error(object sender, ValidationErrorEventArgs e)  
  2. {  
  3.     MessageBox.Show(e.Error.ErrorContent.ToString());  
  4. }  

只是简单的显示验证错误信息,该信息是自定义类中的"名称当中不可包含数字"的信息。

 

4、运行结果

A、当输入一个数字的时候:

 

但是这里会有一个问题,就是在错误信息“1”的基础上在输入一个“1”的时候,消息对话框将弹出两次,这是因为处理验证异常的方法

TextBox_Error的参数e.Error.ErrorContent在处理完一次之后仍会包含这个信息,所以无论后面输入的信息是否合法,第一次非法的信息都将会存在,所以要对这个对象进行Null的处理,代码如下:

[c-sharp] view plaincopy
  1. private void TextBox_Error(object sender, ValidationErrorEventArgs e)  
  2. {  
  3.     if (e.Error.ErrorContent == null)  
  4.     {  
  5.         return;  
  6.     }  
  7.   
  8.     MessageBox.Show(e.Error.ErrorContent.ToString());  
  9.     e.Error.ErrorContent = null;  
  10. }  

 

0 0
原创粉丝点击