Silverlight中的数据绑定3
数据转换
Silverlight中实现数据转换的机制与ASP.NET应该讲是同样的思想,只不过ASP.NET中似乎淡化了手动编写关于数据转换的部分,在Silverlight中我们实现数据转换需实现接口IValueConverter,其位于System.Windows.Data中,IValueConverter其包含两个方法:
Convert():当数据从数据源发送到绑定目标时调用
ConvertBack():当数据从绑定目标发送回绑定源时调用
只有双向绑定时才需要真正实现这两个方法,当单向绑定时,只需实现Convert(),对于ConvertBack()可以使用throw new NotImplementException形式的代码填充。下面仍然以之前的示例为基础,实现FirstName与LastName中的内容为首字母大写形式。
首先仍然沿用先前的Person类:
public class Person:INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public Person() { } private string firstName; public string FirstName { get { return firstName; } set { firstName = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("FirstName")); } } } private string lastName; public string LastName { get { return lastName; } set { lastName = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("LastName")); } } } }
然后实现一个基于IValueConverter的类,完整代码:
namespace DataBindSilverlight { public class UCFirst:IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { var name = (string)value; if (name.Length > 0) { var firstname = name.Substring(0,1); name = firstname.ToUpper() + name.Substring(1); } return name; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return (string)value; } } }
这两步工作完成后,下面的工作即是需要在XAML标记中告知Silverlight使用此转换器,首先,定义一个XML前缀,使得XAML可以访问DataBindSilverlight 空间中的类,代码为:<Canvas xmlns:local="clr-namespace:DataBindSilverlight"/> 第二步则是创建一个Resource子元素,其可以使用DataBindSilverlight,包括UCfirst转换器,这里我们将UCfirst作为内部资源加载,代码:
<Canvas.Resources>
<local:UCFirst x:Key="ucfirstConverter"></local:UCFirst>
</Canvas.Resources>
以上代码添加了一个键x:Key,用来对资源的引用,接下来在TextBox元素中提供转换器的名称
<TextBox Name="textBlock4" Text="{Binding LastName, Mode=TwoWay,Converter={StaticResource ucfirstConverter}}" />
关键字StaticResouces表示使用的资源是内部资源,ucfirstConverter是分配给<local:UCFirst/>的键值。 那么我们已经完成了整个XAML的代码的设计:
代码
<Grid x:Name="PersonalPanel" Background="White"><Canvas xmlns:local="clrnamespace:DataBindSilverlight"><Canvas.Resources><local:UCFirst x:Key="ucfirstConverter"></local:UCFirst></Canvas.Resources><TextBox Height="23" HorizontalAlignment="Left" Margin="88,53,0,0" Name="textBlock3" Text="{Binding FirstName,Mode=TwoWay,ValidatesOnExceptions=True,NotifyOnValidationError=True}"BindingValidationError="showError"VerticalAlignment="Top" /><TextBox Height="23" HorizontalAlignment="Left" Margin="89,89,0,0" Name="textBlock4" Text="{Binding LastName, Mode=TwoWay, Converter={StaticResource ucfirstConverter},ValidatesOnExceptions=True,NotifyOnValidationError=True}" BindingValidationError="showError" VerticalAlignment="Top" /><Canvas Canvas.Left="120"><Polygon Fill="Black" Points="0,5,10,0,10,10" MouseLeftButtonDown="prev"></Polygon><Polygon Fill="Black" Points="15,0,15,10,25,5" MouseLeftButtonDown="next"></Polygon><TextBlock Text="Reverse" Canvas.Left="40" Canvas.Top="20" FontSize="13" MouseLeftButtonDown="reverse"></TextBlock></Canvas></Canvas></Grid>
后台代码其实没有变化,为了方便,仍然贴出来
private int pos = -1; private Person[] persons; public MainPage() { InitializeComponent(); persons = new Person[] { new Person{FirstName="david",LastName="Grenn"}, new Person{FirstName="dam",LastName="white"}, new Person{FirstName="tom",LastName="Smith"}, }; } public void prev(object sender, MouseButtonEventArgs e) { if (pos > 0) pos--; bind(); } public void next(object sender, MouseButtonEventArgs e) { if (pos < persons.Length - 1) pos++; bind(); } private void bind() { PersonalPanel.DataContext = persons[pos]; }
尽管在硬编码中,我们看到的是小写字母单词呈现的单词,但是运行时,已经成功的将其首字母改变为大写形式。
数据验证
当绑定的数据发生更改时,如果需要确保新数据仍然符合某些预先设定的规则,我们基于前面的数据转换示例扩展这一功能首先更新XAML文件,在TextBox元素中提供绑定信息时设置ValidatesOnExceptions,NotifyOnValidationError两个属性为True
XAML完整代码:
<Grid x:Name="PersonalPanel" Background="White"><Canvas xmlns:local="clr-namespace:DataBindSilverlight"><Canvas.Resources><local:UCFirst x:Key="ucfirstConverter"></local:UCFirst></Canvas.Resources><TextBox Height="23" HorizontalAlignment="Left" Margin="88,53,0,0" Name="textBlock3" Text="{Binding FirstName, Mode=TwoWay,ValidatesOnExceptions=True,NotifyOnValidationError=True}" BindingValidationError="showError" VerticalAlignment="Top" /><TextBox Height="23" HorizontalAlignment="Left" Margin="89,89,0,0" Name="textBlock4" Text="{Binding LastName, Mode=TwoWay, Converter={StaticResource ucfirstConverter},ValidatesOnExceptions=True,NotifyOnValidationError=True}" BindingValidationError="showError" VerticalAlignment="Top" /><Canvas Canvas.Left="120"><Polygon Fill="Black" Points="0,5,10,0,10,10" MouseLeftButtonDown="prev"></Polygon><Polygon Fill="Black" Points="15,0,15,10,25,5" MouseLeftButtonDown="next"></Polygon><TextBlock Text="Reverse" Canvas.Left="40" Canvas.Top="20" FontSize="13" MouseLeftButtonDown="reverse"></TextBlock></Canvas></Canvas></Grid>
注意BindingValidationError设置了出现异常的事件处理程序,showError方法的第2个参数类型为ValidationErrorEventArgs, 可通过访问该参数获取相关信息,
public void showError(object sender,ValidationErrorEventArgs e) { //异常不会冒泡 e.Handled = true; if (e.Action == ValidationErrorEventAction.Added) { (e.OriginalSource as TextBox).Text = "**Error**"; } }
ValidationErrorEventAction枚举包含2个值:Added 新验证错误已经信号
Removed 之前的错误输入已经纠正
运行后,当输入的值为空时,异常会抛出(F5忽略该异常),单击前进或后退,返回该记录时,文本会发送改变