传统的验证方法
开发应用程序最基本的的工作内容是进行数据验证。Silverlight的应用程序也不例外。Silverlight应用一定程度上类似于Windows Form应用。其数据验证可以用Winform传统的方法,如在准备提交时的代码中逐项检查数据的合法性。例如一个窗体中有若干输入框,和一个提交按钮。输入完毕后,点击提交按钮。我们可以在提交按钮Click事件处理程序中检查每个输入框的输入合法性。如果不合法,或者用一个弹出窗口提示用户,或者用别的一些方式(这些方式很多的,完全取决于UI设计),再之后就将光标停到有非法值的输入框,等待用户更正。
例如下面的代码:
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:navigation ="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:uriMapper ="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation"
xmlns:d ="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc ="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sdk ="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
x:Class ="SilverlightApplication1.MainPage"
mc:Ignorable ="d" d:DesignWidth ="640" d:DesignHeight ="480" >
< Grid Height ="480" x:Name ="grid1" Width ="640" >
< sdk:Label Height ="19" x:Name ="label1" Width ="52" Content ="学生姓名" HorizontalContentAlignment ="Left" HorizontalAlignment ="Left" Margin ="32,113,0,0" VerticalAlignment ="Top" />
< TextBox Height ="23" x:Name ="textBox1" Width ="110" HorizontalAlignment ="Left" Margin ="109,109,0,0" HorizontalContentAlignment ="Left" VerticalAlignment ="Top" />
< Button Content ="打印" Height ="24" x:Name ="button1" Click ="button1_Click" Margin ="43,233,0,0" VerticalAlignment ="Top" HorizontalAlignment ="Left" Width ="70" />
< ComboBox Height ="24" HorizontalAlignment ="Left" Margin ="109,147,0,0" x:Name ="comboBox1" VerticalAlignment ="Top" Width ="110" >
< ComboBoxItem Content ="男" />
< ComboBoxItem Content ="女" />
</ ComboBox >
< sdk:Label Content ="性别" Height ="19" HorizontalAlignment ="Left" HorizontalContentAlignment ="Left" Margin ="32,147,0,0" x:Name ="label2" VerticalAlignment ="Top" Width ="52" />
< sdk:Label Height ="32" HorizontalAlignment ="Left" Margin ="68,35,0,0" x:Name ="label3" VerticalAlignment ="Top" Width ="141" Content ="学生档案管理" FontSize ="16" />
< Button Content ="保存" Height ="23" Margin ="134,233,0,0" x:Name ="button2" VerticalAlignment ="Top" Click ="button2_Click" HorizontalAlignment ="Left" Width ="75" />
</ Grid >
</ UserControl >
cs代码:
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Printing;
namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
void pDoc_PrintPage( object sender, PrintPageEventArgs e)
{
e.PageVisual = this ;
// throw new NotImplementedException();
}
private void button1_Click( object sender, RoutedEventArgs e)
{
PrintDocument pDoc = new PrintDocument();
pDoc.PrintPage += new EventHandler < PrintPageEventArgs > (pDoc_PrintPage);
pDoc.Print( " 打印本页 " );
}
private void button2_Click( object sender, RoutedEventArgs e)
{
if (textBox1.Text.Length == 0 )
{
MessageBox.Show( " 学生姓名必须输入 " );
textBox1.Focus();
}
}
private void grid1_Loaded( object sender, RoutedEventArgs e)
{
grid1.DataContext = new StudentInfo();
}
}
}
这个验证是检查学生姓名是否输入了。如果没有输入就弹出一个消息窗口,要求输入学生姓名。如图:
再之后将光标定位到学生姓名输入框。这是最传统的Winform输入验证。我们还是可以沿用。
用数据绑定的方式来验证数据
除了传统的方法之外,微软还提供了另外一种方式来实现数据合法性的验证,即:用客户端数据绑定来验证输入的数据。下面介绍一下。通过定义实现接口INotifyPropertyChanged的数据对象,来实现数据验证。
首先创建数据对象,这个数据对象必须有get和set。
using System.ComponentModel;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace SilverlightApplication1
{
public class StudentInfo : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private string _name = null ;
private byte _gender = 0 ;
public string Name
{
get
{
return _name;
}
set
{
if ( string .IsNullOrEmpty(value))
throw new ArgumentException( " Student Name is required. " );
if (value.Length < 30 )
throw new ArgumentException( " Student Name is too long. " );
_name = value;
OnPropertyChanged( " name " );
}
}
public byte Gender
{
get
{
return _gender;
}
set
{
_gender = value;
OnPropertyChanged( " gender " );
}
}
private void OnPropertyChanged( string propertyName)
{
PropertyChanged( this , new PropertyChangedEventArgs(propertyName));
}
}
}
编译一下。保证编译成功。这对后面的只能提示有用。切记。
XAML页面修改如下:
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:navigation ="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:uriMapper ="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation"
xmlns:d ="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc ="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sdk ="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" xmlns:local ="clr-namespace:SilverlightApplication1"
x:Class ="SilverlightApplication1.MainPage"
mc:Ignorable ="d" d:DesignWidth ="640" d:DesignHeight ="480" >
< Grid Height ="480" x:Name ="grid1" Width ="640" Loaded ="grid1_Loaded" >
< Grid.DataContext >
< local:StudentInfo />
</ Grid.DataContext >
< sdk:Label Height ="19" x:Name ="label1" Width ="52" Content ="学生姓名" HorizontalContentAlignment ="Left" HorizontalAlignment ="Left" Margin ="32,113,0,0" VerticalAlignment ="Top" />
< TextBox Height ="23" x:Name ="textBox1" Width ="110" HorizontalAlignment ="Left" Margin ="109,109,0,0" HorizontalContentAlignment ="Left" VerticalAlignment ="Top" Text =" {Binding Mode=TwoWay, UpdateSourceTrigger=Explicit, NotifyOnValidationError=True, ValidatesOnExceptions=True, Path=Name} " />
< Button Content ="打印" Height ="24" x:Name ="button1" Click ="button1_Click" Margin ="43,233,0,0" VerticalAlignment ="Top" HorizontalAlignment ="Left" Width ="70" />
< ComboBox Height ="24" HorizontalAlignment ="Left" Margin ="109,147,0,0" x:Name ="comboBox1" VerticalAlignment ="Top" Width ="110" >
< ComboBoxItem Content ="男" />
< ComboBoxItem Content ="女" />
</ ComboBox >
< sdk:Label Content ="性别" Height ="19" HorizontalAlignment ="Left" HorizontalContentAlignment ="Left" Margin ="32,147,0,0" x:Name ="label2" VerticalAlignment ="Top" Width ="52" />
< sdk:Label Height ="32" HorizontalAlignment ="Left" Margin ="68,35,0,0" x:Name ="label3" VerticalAlignment ="Top" Width ="141" Content ="学生档案管理" FontSize ="16" />
< Button Content ="保存" Height ="23" Margin ="134,233,0,0" x:Name ="button2" VerticalAlignment ="Top" Click ="button2_Click" HorizontalAlignment ="Left" Width ="75" />
</ Grid >
</ UserControl >
笔者看英文的书中介绍是用Express Blend来写黄色和蓝色背景部分。笔者试了一下,在Visual Studio里面似乎没有和Blend一样的操作界面。但是不想为了这个功能来装一个Blend。这里介绍一个只用Visual Studio就能实现的方法:
首先找到需要绑定的控件的容器,这里我们想把学生姓名绑定到textBox1,textBox1的容器是grid1。那么在这一行后回车:
输入<Grid.DataContext>,回车
再输入<local:,Visual Studio智能提示,我们从中选择StudentInfo,在输入/>。然后就成了:
< local:StudentInfo />
</ Grid.DataContext >
在容器添加数据上下文之后。在找到textBox1的Text属性。选”Appy Data Binding”.
Source这一页,StudentInfo已经作为DataContext,什么都不用变。点Path页,
选择Name,这里没有Converter,就直接选择Options页。
Mode选TwoWay,UpdateSourceTrigger选:Explicit,勾选NotifiyOnValidationError,ValidatesOnExceptions, ValidateOnNotifyDataErrors。
然后形成了上述XAML的蓝色背景部分。
之后再选grid1,加入grid1_Loaded处理程序。
{
grid1.DataContext = new StudentInfo();
}
这是给grid1的DataContext初始化一个数据对象。
再在保存按钮的click时间处理程序中如此写:
{
var bindingExpression = textBox1.GetBindingExpression(TextBox.TextProperty);
bindingExpression.UpdateSource();
}
这是将textBox1的Text属性绑定到数据对象。 至此,我们可以运行此程序看看效果。因我们现在用的方法是在Set中抛出Exception。不能用Debug模式运行。请用Debug->Start without Debugging来启动程序。
姓名是必须输入的,试试不输入,直接点保存,姓名输入框会有一个红框:
鼠标移到其右上角的小三角处。
数据对象中抛出的Exception信息就会显示出来:
至此已经实现了一种根据数据对象绑定到Silverlight控件的数据验证方法。以上是在Set抛出例外的方法。
微软还为我们实现了一种DataAnnotation的机制。这样需要我们的工程引用System.ComponentModel.DataAnnotations.dll。还要加上:
如下代码:
public string Name
{
get
{
return _name;
}
set
{
var validatorContext = new ValidationContext( this , null , null );
validatorContext.MemberName = " Name " ;
Validator.ValidateProperty(value, validatorContext);
_name = value;
}
}
[StringLength( 30 , ErrorMessage = " 最长30个字符 " )]
public string Name
{
get
{
return _name;
}
set
{
var validatorContext = new ValidationContext( this , null , null );
validatorContext.MemberName = " Name " ;
Validator.ValidateProperty(value, validatorContext);
_name = value;
}
}

以上是DataAnnotation方法来做输入验证。
Silverlight数据验证的安全性
上面说了这么些数据验证方法。都是在客户端浏览器里运行的验证程序。都是不安全的。Silverlight程序就象Javascript程序一样在客户端浏览器中运行。黑客可以解开xap包,修改Silverlight程序。这和黑客可以绕过Javascript是一样的道理。所以基于Silverlight的系统,都必须在服务器端的WCF和web应用中加入严格的数据验证。才能真正保证安全。