首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

22.3.5  构建模式

21章说明了如何定义XSD模式,Visual Studio .NET有一个编辑器,它可以创建XSD模式—— Project菜单中选择Add New Item,再从Data目录中选择XML Schema选项,就可以访问这个编辑器如图22-25所示。把模式命名为TestSchema.xsd

  22-25

这将给项目添加两个新文件:.xsd文件和一个对应的.xsx文件(它由设计器用于为已设计的模式元素存储布局信息)。要为模式创建相应的一组代码,可从Schema中选择Generate Dataset选项,如图22-26所示。

  22-26

选择这个选项会给项目添加一个额外的C#文件,它也显示在Solution ExplorerXSD文件的下面。当对XSD模式进行修改时,这个文件会自动生成,所以不应手工编辑它。该文件是用sxd.exe工具生成的。

Visual Studio .NET编辑器有XSD文件的两个视图:Schema视图和XML视图。单击XML标签,就会看到最初的模式模板:

<?xml version="1.0" encoding="utf-8" ?>

<xs:schema id="TestSchema"

         targetNamespace="http://tempuri.org/TestSchema.xsd"

         elementFormDefault="qualified"

         xmlns="http://tempuri.org/TestSchema.xsd"

         xmlns:mstns="http://tempuri.org/TestSchema.xsd"

         xmlns:xs="http://www.w3.org/2001/XMLSchema">

</xs:schema>

这个XSD脚本在TestSchema.cs文件中生成下述C#代码。在下面的代码中,省略了方法的主体和格式化的内容,以提高可读性。您自己在建立这个示例时,就可以看到生成的代码:

using System;

using System.Data;

using System.Xml;

using System.Runtime.Serialization;

 

[Serializable()]

[System.ComponentModel.DesignerCategoryAttribute("code")]

[System.Diagnostics.DebuggerStepThrough()]

[System.ComponentModel.ToolboxItem(true)]

public class TestSchema : DataSet

{

   public TestSchema() { ... }

 

   protected TestSchema(SerializationInfo info, StreamingContext context)

   { ... }

   public override DataSet Clone() { ... }

   protected override bool ShouldSerializeTables() { ... }

   protected override bool ShouldSerializeRelations() { ... }

   protected override void ReadXmlSerializable(XmlReader reader) { ... }

   protected override System.Xml.Schema.XmlSchema GetSchemaSerializable()

   { ... }

   internal void InitVars() { ... }

   private void InitClass() { ... }

   private void SchemaChanged(object sender,

                  System.ComponentModel.CollectionChangeEventArgs e)

   { ... }

}

把这段代码作为本节的开始,您就可以看到在给XSD模式添加元素后,代码所发生的变化。要注意的两个问题是:XSD模式映射为DataSet,这个DataSet是可以串行化的—— 注意受保护的构造函数可以由ISerializable实现使用。串行化的内容详见11章。

1. 添加元素

要添加一个新的顶层元素,右击工作空间,从关联菜单中选择Add | New Element。这将在屏幕上创建一个未命名的新元素。图22-27显示了为这个示例的Product元素设置的属性。

  22-27

在保存XSD文件时,可以修改该C#文件,并且生成许多新类,如下面的代码所示。下一节将讨论在文件TestSchema.cs中生成的代码的最重要的方面。

   public class TestSchema : DataSet

{

   private ProductDataTable tableProduct;

   [System.ComponentModel.DesignerSerializationVisibilityAttribute

           (System.ComponentModel.DesignerSerializationVisibility.Content)]

   public ProductDataTable Product

   {

      get

      {

         return this.tableProduct;

      }

   }

}

创建了ProductTable类的一个新成员变量,这个对象由Product属性返回,并在更新的InitClass()方法中构造。在这一小段代码中,使用这些类可以从这个文件的类中构造一个DataSet,使用DataSet.Products返回Products数据表。

2. 生成的数据表

为添加到模式模板中的DataTable (Product)生成下面的代码:

public delegate void ProductRowChangeEventHandler

                    (object sender, ProductRowChangeEvent e);

public class ProductDataTable : DataTable, System.Collections.IEnumerable

{

   internal ProductDataTable() : base("Product")

   {

      this.InitClass();

   }

   [System.ComponentModel.Browsable(false)]

   public int Count

   {

      get { return this.Rows.Count;}

   }

   public ProductRow this[int index]

   {

      get { return ((ProductRow)(this.Rows[index]));}

   }

   public event ProductRowChangeEventHandler ProductRowChanged;

   public event ProductRowChangeEventHandler ProductRowChanging;

   public event ProductRowChangeEventHandler ProductRowDeleted;

   public event ProductRowChangeEventHandler ProductRowDeleting;

生成的ProductDataTable类派生于DataTable,其中包括IEnumerable接口的实现。定义了4个事件,当引发这些事件时,会使用上面定义的委托,这个委托的参数是ProductRowChangeEvent类的一个实例,该类也是由Visual Studio .NET定义的。

生成的代码包含一个派生于DataRow的类,它可以对表中的类进行类型安全的访问。创建新行有两种方式:

       调用NewRow (或生成的NewProductRow)方法,返回行类的一个新实例。把这个新行传递给 AddRow()函数(或类型安全的AddProductRow)

       调用AddRow (或生成的AddProductRow)方法,其参数是一个对象数组,数组中的元素对应于表中的每一列。

 

AddProductRow方法如下所示:

public void AddProductRow(ProductRow row)

{

   this.Rows.Add(row);

}

public ProductRow AddProductRow ( ... )

{

   ProductRow rowProductRow = ((ProductRow)(this.NewRow()));

   rowProductRow.ItemArray = new Object[0];

   this.Rows.Add(rowProductRow);

   return rowProductRow;

}

从代码中可以看出,第二个方法创建了一个新行,把该行插入到DataTableRows集合中,再把该对象返回给调用者。DataTable上的其他方法用于引发事件。

3. 生成的数据行

生成的 ProductRow 类如下所示:

public class ProductRow : DataRow

{

   private ProductDataTable tableProduct;

   internal ProductRow(DataRowBuilder rb) : base(rb)

  {

    this.tableProduct = ((ProductDataTable)(this.Table));

  }

   public string Name { ... }

   public bool IsNameNull { ... }

   public void SetNameNull { ... }

  // Other accessors/mutators omitted for clarity

}

把属性添加到元素上时,就会把一个特性添加到生成的DataRow类上,如上述代码所示。该特性与属性有相同的名称,所以在上面的示例中,Product行包含NameSKUDescriptionPrice特性。

对于每个新添加的属性,都对.cs文件进行了几处修改。在下面的示例中,假定添加了一个类型为int的属性ProductId

首先给ProductDataTable(派生于DataTable)添加一个私有成员,即新的DataColumn

private DataColumn columnProductId;

用属性ProductIDColumn来连接,这个属性被定义为internal

internal DataColumn ProductIdColumn

{

   get { return this.columnProductId; }

}

上面的AddProductRow()方法也做了修改,该函数现在带有一个整型参数ProductID,并存储了在新建列中输入的值:

public ProductRow AddProductRow ( ... , int ProductId)

{

   ProductRow rowProductRow = ((ProductRow)(this.NewRow()));

   rowProductRow.ItemArray = new Object[] { ... , ProductId};

   this.Rows.Add(rowProductRow);

   return rowProductRow;

}

最后在ProductDataTable中修改InitClass()方法:

private void InitClass()

{

  ...

  this.columnProductID = new DataColumn("ProductID", typeof(int), null,

                               System.Data.MappingType.Attribute);

  this.Columns.Add(this.columnProductID);

  this.columnProductID.Namespace = "";

}

这段代码创建了新的DataColumn,并把它添加到DataTableColumns集合中。DataColumn构造函数的最后一个参数定义了在把DataSet保存到XML文件中时,该列如何映射回XML上。

更新ProductRow类,并给这个列添加一个访问器:

public int ProductId

{

   get { return ((int)(this[this.tableProduct.ProductIdColumn])); }

   set { this[this.tableProduct.ProductIdColumn] = value; }

}

4. 生成的EventArgs

最后一个添加到源代码中的类是EventArgs的一个派生类,它提供的方法可以直接访问已经改变(或者正在改变)的行,以及应用到该行上的操作。这里为了简洁起见,省略了这段代码。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论