在开发过程中,经常需要对数据进行验证,以确保数据的准确性和完整性。本文将介绍如何在.NET Framework 3.5及以上版本中使用WPF Toolkit的DataGrid控件进行数据验证。WPF Toolkit是一个开源的WPF控件集合,提供了许多实用的控件,其中就包括DataGrid。DataGrid是一个强大的数据展示和编辑控件,支持数据绑定、排序、筛选等高级功能。
在本例中,将使用MVVM模式进行开发。MVVM是一种设计模式,用于分离视图(View)和模型(Model)的逻辑,使得代码更加清晰和易于维护。在MVVM模式中,视图负责展示数据,模型负责存储数据,而视图模型(ViewModel)则负责处理视图和模型之间的交互逻辑。
最近,需要在一个表格控件中验证数据。不想购买第三方组件,而是决定使用WPF Toolkit的DataGrid。在阅读了Colin Eberhardt的优秀文章后,意识到在.NET Framework 3.5中使用时,尤其是当数据不是由用户更改而是通过程序添加时,会遇到一些问题。需要实现一个小工具,可以通过解压缩Zip文件进行部署。因此,不想让用户仅仅为了解决验证问题而需要安装.NET Framework 4.0。
应用程序使用MVVM模式。如果还没有听说过它,建议阅读Josh Smith的好文章。验证发生的地方是一个名为PersonVM的类。这个类包含以下属性:
string FirstName
string LastName
bool HasJob
(string JobName)
需要验证两件事:首先,名字和姓氏只能包含A-Za-z字符和空格。其次,不允许一个人设置HasJob标志,但JobName为空,或者反之。
第一条规则可以通过验证每个名称属性来检查。要检查第二条规则,仅仅验证一个属性是不够的,而是需要多个属性。这种验证发生在整个Person对象上。
验证是在以下PersonVM索引器中实现的(由IDataError接口所需):
public string this[string columnName]
{
get
{
// apply property level validation rules
if (columnName == "FirstName")
{
if (String.IsNullOrEmpty(this.FirstName))
return "First Name needs to be filled";
if (!MyNameEx.Match(this.FirstName).Success)
return "First Name may only contain characters or spaces";
}
if (columnName == "LastName")
{
if (String.IsNullOrEmpty(this.LastName))
return "Last Name needs to be filled";
if (!MyNameEx.Match(this.LastName).Success)
return "Last Name may only contain characters or spaces";
}
// Method ValidateJob applies object level validation. In this example the consistency
// of the properties HasJob and JobName is checked on object level. An error is
// announced for JobName only. Otherwise the red error border would be presented for
// the JobName and the HasJob field and the error correction would be inconvenient
// for the user - try it out by uncommenting following line
if (columnName == "JobName" || columnName == "HasJob")
if (columnName == "JobName")
{
return ValidateJob();
}
return "";
}
}
ValidateJob方法如下:
private string ValidateJob()
{
if (!this.HasJob && !String.IsNullOrEmpty(this.JobName))
{
return "Job Name is given, but Job Flag is not set!";
}
if (this.HasJob && String.IsNullOrEmpty(this.JobName))
{
return "Job Name is not given, but Job Flag is set!";
}
return "";
}
IDataError的第二种方法没有为PersonVM单独编写,可以放入一个基类或帮助类中。
多字段验证需要通过一个字段来通知 - 例如示例中的JobName - 因为用户不能在一步中编辑多个字段来纠正多字段错误。因此,当HasJob复选框更新时,需要模拟JobName已更改。这种通知是在HasJob setter中完成的:
public Boolean HasJob
{
get
{
return myHasJob;
}
set
{
myHasJob = value;
NotifyPropertyChanged("JobName");
NotifyErrorChanged();
}
}
DataGrid的相应XAML代码如下:
<Window x:Class="ValidationInWpfDatagrid.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dg="http://schemas.microsoft.com/wpf/2008/toolkit"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<dg:DataGrid Name="myDataGrid" AutoGenerateColumns="False" ItemsSource="{Binding PersonList}" CanUserAddRows="True">
<dg:DataGrid.Resources>
<Style TargetType="{x:Type dg:DataGridCell}">
<Setter Property="TextBlock.ToolTip" Value="{Binding Error}"/>
</Style>
</dg:DataGrid.Resources>
<dg:DataGrid.Columns>
<dg:DataGridTextColumn Header="FirstName" Binding="{Binding Path=FirstName, ValidatesOnDataErrors=True}" Width="*"/>
<dg:DataGridTextColumn Header="LastName" Binding="{Binding Path=LastName, ValidatesOnDataErrors=True}" Width="*"/>
<dg:DataGridCheckBoxColumn Header="Job Flag" Binding="{Binding Path=HasJob, ValidatesOnDataErrors=True}" Width="*"/>
<dg:DataGridTextColumn Header="Job's Name" Binding="{Binding Path=JobName, ValidatesOnDataErrors=True}" Width="*"/>
</dg:DataGrid.Columns>
</dg:DataGrid>
<Button Grid.Row="1" Name="myBtnAddPerson" Content="Add Person" Command="{Binding AddPersonCommand}"/>
</Grid>
</Window>