数据点

使用 Silverlight 3 和 DataForm 进行数据验证

JOHN PAPA

构建可靠的 Silverlight 应用程序用于编辑和验证数据获得整个很多更容易在引入数据窗体控件的 Silverlight 3 中。数据窗体控件中包含多种可以帮助创建窗体,添加、 编辑、 删除和浏览的数据集的功能。在数据窗体的最大好处是其灵活性和自定义选项。

在这个月已经列中我将显示数据窗体控件的工作原理以及如何可以对其进行自定义,,并且我 ’ll 操作中演示。我 ’ll 首先演示示例应用程序使用几种功能绑定、 浏览、 编辑和验证使用该数据窗体的数据。然后我 ’ll 遍历时指出基本要求使用控件和自定义建议示例应用程序如何。在数据窗体不需要在 DataAnnotations,但它们可能会影响外观、 验证方面和在数据窗体的行为。在 DataAnnotations 还可以指示一个调用属性或整个实体的自定义验证方法。我将介绍如何实现在实体上的在 DataAnnotations 以及如何编写您自己的自定义 PAPAvalidation 方法。从 MSDN 代码库 (msdn.microsoft.com/mag200910DataPoints),可以下载本文中的所有代码。

什么 ’s 在 Endgame?

在深入探讨代码之前, let’s 一下演示导航、 验证和在数据窗体的编辑功能的示例应用程序。图 1 显示显示员工和一个数据窗体可以编辑每个雇员记录的位置的列表对数据网格。员工数据网格中的可以被定位,更改即当前所选的员工。在数据窗体绑定到同一组员工,并接收该员工。

工具栏

显示图 1 已放处于编辑模式,因此用户在数据窗体可使更改,并可以保存或取消它们。在数据窗体的右上方的工具栏显示图标,用于编辑 (铅笔)、 添加新记录 (加号) 和删除记录 (减号)。这些按钮可样式,并根据需要禁用。该按钮的状态是由接口实现该的实体时,可以通过在数据窗体上设置属性自定义其可见性决定的。

标签

旁边或上面控件可以放置在数据窗体中的每个文本框的标题。可以使用显示 DataAnnotations 属性元数据驱动的标签内容。DataAnnotations 属性放在该的实体的属性在这种情况下该雇员实体它们帮助源等不是字段标签中显示该文本在数据窗体信息上。

DescriptionViewer

当在数据窗体处于编辑模式 (如的图 1 所示) 时, 用户可以悬停旁边的每个文本框控件,若要查看一个提供有关如何在字段中输入更多的信息的工具提示标题旁边的图标。此功能由该数据窗体放 DescriptionViewer 控件绑定的文本框控件旁边时实现。在 DescriptionViewer 的工具提示中显示的文本也是从 DataAnnotations 显示属性送纸。


图 1 验证和使用数据窗体编辑

取消并提交

在编辑模式中时启用在该数据窗体的底部取消按钮。在编辑模式下启用保存按钮,并且用户更改该数据窗体中的一个值。可以自定义文本和这些按钮的样式。


图 2 数据窗体的

验证通知

NotificationThe 数据窗体示例中所示的用户已键入一个无效的电子邮件地址和电话号码中编辑状态。请注意无效字段的字段标题位于红色,文本框将以红色 bordered 带有红色标志在右上角。当用户将光标放在一个失效控件中时,描述什么进行以更正此问题有一条消息将出现工具提示。图 1 也显示在屏幕的底部,验证错误的列表。所有这些功能支持的数据窗体 DataAnnotations,可以使用自定义的样式为自定义的外观和感觉。验证规则的送纸方式从几个以指示必需的字段或自定义规则的现成的规则 DataAnnotations。

在数据窗体的设计

在 Silverlight 工具箱中找到的在 DataForm 可以添加到项目中一次 System.Windows.Controls.Data.DataForm.Toolkit.dll 已被引用程序集。在数据窗体可以创建具有很少的安装程序。一次拖动到设计图面中混合或在 XAML 中创建通过只需将该 ItemsSource 在数据窗体的设置为一个实体集合在数据窗体将自动生成字段显示,然后编辑相应的功能。下面的 XAML 中将生成的图 2 所示,数据窗体:

<dataFormToolkit:DataForm x:Name="dataForm" ItemsSource="{Binding Mode=OneWay}" />

注意:在绑定模式设置为单向在前面的示例中只用于显式。不需要。但是,我很有用的清晰度和可支持性若要显式设置绑定模式。

附加设置可以被挂接到该数据窗体调整其功能。常用设置包括的的图 3 所示。

图 3 常规数据窗体的自定义

通常,最好数据窗体已经视觉功能,来调整它们与您的应用程序的外观的样式。在数据窗体的几个方面可以使用文档、 app.xaml 或资源字典中的资源被样式。有几个可以设置的样式从 Expression Blend 部分屏幕快照中的 图 4 所示。请注意 CancelButtonStyle 和该 CommitButtonStyle 都设置为一个值。这是什么使按钮蓝色外观中在屏幕底部的图 1 的中所示。在数据窗体本身可以被样式通过设置样式属性。数据窗体,如 ValidationSummary 或数据字段的各个方面也可以被样式。

通过将某些设置在数据窗体的这些更常见的属性,以及一些基本样式,我们获得外观和显示在的图 1 中的功能。这篇文章中包含的示例应用程序的设置如的图 5 所示。请注意 AutoEdit 和自动提交两个设置为 false,因此要求在数据窗体被显式进入编辑模式由用户单击上的编辑按钮和用户单击保存按钮将更改提交。


图 4 数据窗体的样式

导航按钮省略,则意味着工具栏不会显示导航选项 CommandButtonsVisibility 属性。如果我们包括此选项,通过向该 CommandButtonsVisibility 关键字导航或者通过将设置更改为关键字所有在数据窗体还将显示导航工具栏按钮。因为 CommandButtonsVisibility 属性中包含提交和取消按钮,它们将可见。在数据窗体具有不被编辑时还,的图 6 所示,将禁用取消按钮。导航按钮允许用户移动的记录的集合。但是,此示例应用程序中,用户还可以导航还绑定到该数据窗体为相同的数据集,因为使用该数据绑定 DataGrid。因此,关闭了导航按钮在工具栏中只为一个设计选项因为导航功能已经可以实现通过数据网格。

DataAnnotations

很多,数据窗体的功能是由 DataAnnotations 属性放置在实体数据绑定到该数据窗体上驱动的。一旦您引用程序集 System.ComponentModel.DataAnnotations.dll 在 DataAnnotations 不可用。在数据窗体检查属性,并相应地应用它们。图 7 显示几个 DataAnnotations 属性可以装饰的实体的属性,并描述它们的效果。

图 5 自定义数据窗体

<dataFormToolkit:DataForm x:Name="dataForm"
                 ItemsSource="{Binding Mode=OneWay}"
                 BorderThickness="0"
                 FontFamily="Trebuchet MS" FontSize="13.333"
                 CommitButtonContent="Save"
                 CancelButtonContent="Cancel"
                 Header="Employee Details"
                 AutoEdit="False"
                 AutoCommit="False"
                 AutoGenerateFields="True"
                 CommandButtonsVisibility="Edit, Add, Delete, Commit, Cancel"
                 CommitButtonStyle="{StaticResource ButtonStyle}"
                 CancelButtonStyle="{StaticResource ButtonStyle}"
                 DescriptionViewerPosition="BesideLabel"
                 LabelPosition="Left" />

显示属性源数据窗体已经标签和 DescriptionViewer 用名称和说明的参数分别。如果省略,在数据窗体将自动生成这些控件使用属性的名称的值。请注意在图 8 中的雇员实体已经名字属性用 3 DataAnnotations 属性修饰。显示属性指示标签应该显示文本 “ 名 ”,并且在 DescriptionViewer 应显示 “ 雇员已经名字 ” 的一个工具提示。

该要求的属性指示一个值必须输入为名字属性。必填属性类似于所有的验证属性接受一个 ErrorMessage 参数。ErrorMessage 参数指示一个失效控件的工具提示在和中 ValidationSummary 控件在数据窗体中将显示的消息。StringLength 属性为名字属性设置为指示该字段不能超过 40 的字符,如果那样,将显示一条错误消息。

图 8 中的该代码显示了当在属性上设置一个值,验证调用该方法。验证是基类 ModelBase 使用在此示例中的所有实体中创建一种方法。此方法通过检查它对所有 DataAnnotations 属性来验证该属性。如果有任何的未能中, 它将引发异常,没有将该属性设置为值无效,指示该数据窗体向用户通知。图 1 显示清空该名字字段,因为它是所需的结果。

以便可以验证每个属性设置时在每个属性 setter 调用 ModelBase 类已经验证方法。该方法接受新值和验证属性的名称。这些参数中传递验证类已经 ValidateProperty 方法不会在实际验证该属性值:

protected void Validate(object value,
string propertyName) {
Validator.ValidateProperty(value,
new ValidationContext(this, null, null) {
MemberName = propertyName });
}

该验证是静态类,允许您使用多个不同的技术执行验证:

  • ValidateProperty 方法检查单个属性的值,并引发 DataAnnotations.ValidationException,如果值无效。
  • ValidateObject 方法检查整个实体上的所有属性,并引发 DataAnnotations.ValidationException,如果任何值无效。
  • TryValidateProperty 方法执行相同的验证检查,作为 ValidateProperty,除外,它返回一个布尔值,而不是引发异常。
  • TryValidateObject 方法执行相同的验证检查,作为 ValidateObject,除外,它返回一个布尔值,而不是引发异常。
  • ValidateValue 方法接受值,并验证属性的集合。如果值失败的任何属性,则将引发一个 ValidationException。
  • TryValidateValue 方法执行相同的验证检查,作为 ValidateValue,不同之处在于,它返回一个布尔值,而不是引发异常。

图 7 常规 DataAnnotations

图 8 名字属性以 DataAnnotations

private string firstName;
[Required(ErrorMessage = "Required field")]
[StringLength(40, ErrorMessage = "Cannot exceed 40")]
[Display(Name = "First Name", Description = "Employee's first name")]
public string FirstName
{
get { return firstName; }
set
{
if (firstName == value) return;
var propertyName = "FirstName";
Validate(value, propertyName);
firstName = value;
FirePropertyChanged(propertyName);
}
}

我还创建 ModelBase 类名为 IsValid,如下所示调用该 TryValidateObject 方法中的一种方法。 此方法可以调用实体上,以确定它是否处于有效状态的任何时候:

public bool IsValid() {
return Validator.TryValidateObject(this,
new ValidationContext(this, null, null),
this.validationResults, true);
}

图 9 的自定义属性的有效性

public static class EmployeeValidator
{
public static ValidationResult ValidateAge(int age)
{
if (age > 150)
return new ValidationResult("Employee's age must be under 150.");
else if (age <= 0)
return new ValidationResult(
"Employee's age must be greater than 0.");
else
return ValidationResult.Success;
}
}

自定义验证

当一个罐头的 DataAnnotations 的一组属性并不已经足够了您可以创建自定义验证的方法和应用到整个对象或属性值。 验证方法必须是静态的并返回一个 ValidationResult 对象。 ValidationResult 对象是包含该邮件将被绑定到该数据窗体在汽车。 图 9 显示验证值介于 0 和 150 该 ValidateAge 自定义验证方法。 这是一个简单的示例,并且可能已使用一个范围属性。 但是,创建特定的方法允许它通过验证多个实体重复使用。

也可以创建自定义验证方法,来验证整个对象。 ValidateEmployee 方法接受整个雇员实体,并检查中确定如果实体处于有效状态的多个属性。 这是非常有用的强制执行实体级验证,如下所示:

public static ValidationResult ValidateEmployee(Employee emp) {
string[] memberNames = new string[] { "Age", "AnnualSalary" };
if (emp.Age >= 50 && emp.AnnualSalary < 50000)
return new ValidationResult(
"Employee is over 50 and must make more than $50,000.",
memberNames);
else
return ValidationResult.Success;
}

引发一个或多个 ValidationExceptions (请参见图 10) 时,通过在数据窗体中显示验证摘要控件。 中粗体字母显示它旁边显示验证消息时突出显示该字段的名称。 为该 ValidationSummary 样式可以也进行自定义使用资源,如果需要。


图 10 验证摘要

influencers

在数据窗体所需的提示,从 DataAnnotations,以及从其绑定的数据源实现的接口。 渚嬪的方式  雇员实体实现 IEditableObject 接口。 此接口强制 BeginEdit CancelEdit,EndEdit 方法通过在数据窗体在调用适当的时间时正在编辑该数据窗体的实现。 在示例应用程序中我使用这些方法实现一种取消行为,以便用户可以按取消按钮,并还原原始实体值。

这是通过 BeginEdit 方法 (命名缓存) 中创建实体的实例并将从该实体中复制原始值中实现的。 在 EndEdit 方法 CancelEdit 方法将复制回缓存实体因此恢复其原始状态,原始实体的所有值窗体时,请清除高速缓存对象。

在数据窗体可以看到它绑定到该集合是一个 CollectionViewSource 时, 它将支持编辑、 排序、 筛选和跟踪当前的记录 (也称为货币)。 它还确保在数据窗体中不允许用户离开的实体无效状态而不修复和提交或取消所做的更改是重要,货币功能。 绑定到一个 PagedCollectionView 的在数据窗体还提供了这些相同的功能,并还提供删除项目的添加项,对项目进行分组。 为自己在 ObservableCollection 不实现接口在数据窗体要查找的绑定到一个 ObservableCollection 将禁用某些这些的功能。

如果您的实体已经包含一个 ObservableCollection 中,可以通过 ObservableCollection 实例传递到集合中,通过它的构造函数创建一个 PagedCollectionView,如下所示:

var employees = new DataService().GetPeople();
PagedCollectionView view = new PagedCollectionView(employees);
this.DataContext = view;

或者,可以创建一个 CollectionViewSource 的员工在 ObservableCollection 传入 CollectionViewSource 已经集合初始值设定项并在源属性中,设置,如下所示:

var employees = new DataService().GetPeople();
CollectionViewSource view = new CollectionViewSource
{Source = employees};
this.DataContext = view;

结束语

在数据窗体添加大量的值的应用程序通常占用大量代码的和 monotonous 浏览、 编辑和查看数据的过程。 其功能是可自定义以满足您的需要的它可以样式直观地设计您的应用程序已经以混合。

John Papa (johnpapa.net) 是一个高级顾问人员花费夏季里住宿的与他的家人 Yankees 定位棒球风扇。 papa,Silverlight MVP Silverlight 内幕,INETA 扬声器,已编写几个简介册包括其最新,“ 数据驱动服务使用 Silverlight 2 ” (O’Reilly,2009年)。 他经常说出会议,如 VSLive!,DevConnections 和 MIX。