在上一篇《深入ASP.NET数据绑定(上)》中,我们分析了在.NET中的数据绑定语法的一些内部机理。简单说来就是ASP.NET在运行时为我们完成了页面的动态编译,并解析页面的各种服务器端代码,包括数据绑定语法。而数据绑定的语法虽是一些<%# %>代码块,在生成的代码中,仍然使用了服务器端控件以及在DataBinding事件调用DataBinder.Eval方法来完成数据的绑定工作。所有的数据绑定模板控件都使用了这样的机制来进行数据的单向绑定,在.NET 2.0中新增了双向的数据绑定方式,主要用在GridView,DetailsView,FormView等数据容器控件中,结合DataSourceControl就可以非常轻松的完成数据的更新和提交工作,而不需要我们手工去遍历输入控件的值。那在这样的双向数据绑定中,ASP.NET又是做了哪些工作,来为我们透明输入控件与字段的取值与对应关系,让我们可以在DataSouceControl中方便得到数据项修改前的值和修改后的值?下面就让我们一起来从一段页面代码开始吧:
1: <asp:DetailsDataSouce ID="DetailsDataSouce1" runat="server">
2: </asp:DetailsDataSouce>
3: <asp:DetailsView ID="detailsView" runat="server" DefaultMode="Edit" DataSourceID="DetailsDataSouce1">
4: <Fields>
5: <asp:TemplateField>
6: <HeaderTemplate>
7: 电流:</HeaderTemplate>
8: <EditItemTemplate>
9: <asp:TextBox ID="textBox1" runat="server" Text='<%# Bind("[电流{a}]") %>'></asp:TextBox>
10: </EditItemTemplate>
11: </asp:TemplateField>
12: </Fields>
13: </asp:DetailsView>
在一个页面中,定义了如上的一个DetailsView控件,为这个控件指定了ID为DetailsDataSource1的DataSouceControl控件,这个控件是我们自己定义的一个DataSourceControl,它返回的数据字段包括:"ID","电流{a}","电压(v)","备注'","名称]"。我并没有设置DetailsView的AutoGenerateRows属性的值,默认情况下,它是为我们自动的生成这些字段的对应的数据显示和输入控件。除此之外,我们还另外添加了一个数据模板字段,在这个模板中指定了编辑模板。在编辑模板中我使用了<%# Bind("")%>这样的语法,将textBox1与"[电流{a}]"字段双向绑定起来。
为什么这里的字段都有一些特殊呢?因为我原先的意图是除了分析绑定语法以外,还要测试哪些特殊字符无法使用数据绑定语法来绑定数据的。这个在下篇文章中会具体介绍。
Bind与Eval不一样,这样的Bind并不Page或TemplateControl的一个方法,事实上我们应该把它当成一个关键字来看待,因为在ASP.NET的双向数据绑定当中,并没有这样的一个函数存在,它的存在是只是告诉ASP.NET动态编译页面类时,将这个语法编译成一定的代码格式,并生成一些函数代理来达到双向数据交流的目的。
那么这一段代码,动态编译生成的服务器代码又是如何的呢?让我们反编译动态程序集,里面会找到用于创建DetailsView的__BuildControldetailsView的私有方法,在这里会调用到一些其它内部方法,我们不要让这些方法来干扰我们的视线,直接找到创建如上模板字段的方法:
1: [DebuggerNonUserCode]
2: private TemplateField __BuildControl__control5()
3: {
4: TemplateField field = new TemplateField();
5: field.HeaderTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control6));
6: field.EditItemTemplate = new CompiledBindableTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control7), new ExtractTemplateValuesMethod(this.__ExtractValues__control7));
7: return field;
8: }
这里首先把this.__BuildControl__control6作为一个代理函数,用于创建头部模板的内容,也就是如上的“电流:”字段标题。然后才是创建EditItemTemplate,这个模板又被一些的中介模板所代替,我们只需要来关心this.__BuildControl__control7和__ExtractValues__control7即可。__BuildControl__control7是为了编辑数据字段时,将数据字段的值显示在输入控件中(输入控件的初始化,即字段值绑定到输入控件中);而__ExtractValues__control7则是在提交数据时,要找出这个模板内所有的双向绑定字段,将这些字段的值以绑定字段名为Key,以输入控件的值为Value添加了IOrderedDictionary字典中。DetailsView等数据绑定控件调用这些委托代理来收集所有的被双向绑定的字段的最新的值。下面分别是两段函数的代码片段:
1: [DebuggerNonUserCode]
2: private TextBox __BuildControl__control8()
3: {
4: TextBox box = new TextBox();
5: box.TemplateControl = this;
6: box.ApplyStyleSheetSkin(this);
7: box.ID = "textBox1";
8: box.DataBinding += new EventHandler(this.__DataBinding__control8);
9: return box;
10: }
11: public void __DataBinding__control8(object sender, EventArgs e)
12: {
13: TextBox box = (TextBox) sender;
14: IDataItemContainer bindingContainer = (IDataItemContainer) box.BindingContainer;
15: if (this.Page.GetDataItem() != null)
16: {
17: box.Text = Convert.ToString(base.Eval("[电流{a}]"), CultureInfo.CurrentCulture);
18: }
19: }
1: [DebuggerNonUserCode]
2: public IOrderedDictionary __ExtractValues__control7(Control __container)
3: {
4: TextBox box = (TextBox) __container.FindControl("textBox1");
5: OrderedDictionary dictionary = new OrderedDictionary();
6: if (box != null)
7: {
8: dictionary["[电流{a}]"] = box.Text;
9: }
10: return dictionary;
11: }
由上面的代码片段可以了解到,ASP.NET动态编译器是将Bind语法拆分为两部分:绑定输出和读取输入控件值。绑定输出部分与前篇介绍的机制是完全一样的,并且也是调用DataBinder.Eval方法来绑定数据;而读取输入控件值则是会根据页面上控件的类型,以及绑定的控件属性名称,生成一段强类型的控件属性读取代码,并将控件的值保存到dictionay中返回出去。而它全然不知,容器控件是如何将这些值合并起来传给对应的DataSouceControl控件的。
关于数据容器控件而何与DataSouceControl协同工作,并不是我们这里要分析的重点。但是我们可以简单的描述一下工作流程,以DetailsView的数据更新为例:大家通过反编译DetailsView的源码,会找到名称为HandleUpdate的私有方法,在这个方法里面会去处理数据项更新前的值(至于在Web环境中如何保存更新前的值,就需要靠ViewState的强大功能了),和更新后的值(通过ExtractRowValues函数调用类似上面生成的__ExtractValues__control7代理函数来收集所有双向绑定字段的值存到NewValues里面),并将他们分别保存在两个不同的IOrderedDictionary对象(OldValues,NewValues)中。然后将调用对应的DataSouceView的Update方法,传入原字段值和新字段值和一些必须的参数,即可由我们通过重写DataSourceView的方法来得到所有需要更新字段的原始值和新值,并可以对比比较哪些字段值是否发生了变化。NBearDataSource控件就是利用了这样的机制来直接重DataSourceControl和DataSourceView来达到数据的全自动修改和添加方案的。
这里还有一点不得不说,在GridView,DetailsView,并不一定需要使用<%# Bind("")%>语法来实现数据的双向绑定,他们的字段双向绑定可以通过BoundField及它的子控件代替模板控件的绑定语法,一样可以达到双向绑定的目的,简单但没有模板来得灵活。而在存取不同版本的字段值也是类似的机制。
由于这部分涉及到的都是动态和内部代码,如果没有亲自去阅读这些代码,估计还是很难理解。最后我们再来简单总结一下:ASP.NET在模板中双向绑定字段,是通过<%# Bind() %>这样的语法,但是Bind我们更应该把它理解为是一个关键字,而不是一个函数。因为在ASP.NET的控件中,并没有存在这个函数。ASP.NET运行时在编译页面代码时,会把Bind关键字的代码当成两部分来编译:一部分是单向绑定代码;另一部分而是读取对应输入控件的绑定属性,以绑定字段名为Key,添加到IOrderedDictionary中收集返回给数据容器控件(GridView,DetailsView,FormView)等,让它们处理。
总体来说,ASP.NET 2.0的双向绑定机制给我们在提交数据时带来了极大的方便,尽管有些人很排斥DataSourceControl的模式,但是我们不可否认合理应用会大大提高我们的开发效率。希望通过这两篇的介绍,我们能对ASP.NET数据绑定机制有更多的认识。在下一篇的文章中,我们将会介绍一些关于数据绑定方式,性能,以及对字段名的局限性等相关主题。
附上示例工程,本文分析面页是Default3.aspx和App_Web_ryn6wtvv.dll程序集。
发表评论
-
ASP.NET Process Model之一:IIS 和 ASP.NET ISAPI
2010-01-07 22:04 1029前几天有一个朋友在MSN上问我“ASP.NET 从最初的接收到 ... -
深入ASP.NET数据绑定(下)——多样的绑定方式
2010-01-06 19:58 1013在这个系列的上篇中介 ... -
深入ASP.NET数据绑定(上)
2010-01-06 19:55 1053在ASP.NET我们在使用Repeater,DetailsVi ... -
C#与数据结构--二叉树的遍历
2009-07-09 10:30 22116.2.2 二叉树的存储结构 二叉树的存储可分为两种:顺序 ... -
前序遍历二叉树,中序遍历二叉树,后序遍历二叉树 c#实现
2009-07-08 23:31 2231using System.Collections.Generi ... -
如何自己实现IEnumerable和IEnumerator接口以支持foreach语句
2009-07-08 23:25 2421在C#中,凡是实现了IEnumerator接口的数据类型都可以 ... -
IEnumerable与IEnumerator区别
2009-07-08 23:11 2614public interface IEnumerable{ ... -
IList、ICollection、IEnumerable 之辨析
2009-07-08 23:06 3140祖宗:IEnumerable 此接口只有一个方法 GetEn ... -
(c#)数据结构与算法分析 --栈与队列
2009-07-08 22:58 1809栈stack 栈是一种后进后出机制,它只允许访问 ... -
使用ASP.NET Global.asax 文件
2009-05-05 20:00 1140Global.asax 文件,有时候 ... -
ASP.NET VIEWSTATE初探
2009-05-05 17:55 1645一、 ViewState 的作用 与刚接触 ASP. ...
相关推荐
在标题和描述中提到的`("字段名") %>`和`("字段名") %>`是ASP.NET数据绑定表达式,它们用于在页面中显示数据或实现数据的双向绑定。 `Eval`方法用于单向数据绑定,它会从数据源中获取指定字段的值,并将其转换为...
本资源“ASP.NET 1.1入门经典——Visual C#.NET 2003编程篇”提供了一个学习ASP.NET 1.1的基础教程,特别关注了使用C#语言进行编程的方法。Visual C#.NET 2003是.NET Framework 1.1时代的集成开发环境(IDE),它为...
ASP.NET 数据绑定控件是Web开发中用于展示和操作数据的核心组件,它们简化了与数据库或其他数据源交互的过程。在ASP.NET框架中,数据绑定提供了一种声明式的方式来将控件(如GridViews、ListViews、DataLists等)与...
6. **双向数据绑定**:ASP.NET也支持双向数据绑定,例如 `TextBox` 控件的 `Text` 属性,当用户修改文本框的内容时,可以自动更新到数据源。 7. **Entity Framework**:作为ORM(对象关系映射)框架,Entity ...
圣殿祭司的ASP.NET 2.0开发详解——使用C#,很好的asp.net学习课件,涵盖了asp.net各个重要知识点,讲解详细
ASP.NET 2.0开发详解——使用C#.part02ASP.NET 2.0开发详解——使用C#.part02
ASP.NET 2.0开发详解——使用C#.part01ASP.NET 2.0开发详解——使用C#.part01
ASP.NET 2.0开发详解——使用C#.part03ASP.NET 2.0开发详解——使用C#.part03
ASP.NET 2.0开发详解——使用C#.part06ASP.NET 2.0开发详解——使用C#.part06
ASP.NET 2.0开发详解——使用C#.part04ASP.NET 2.0开发详解——使用C#.part04
ASP.NET 2.0开发详解——使用C#.part05ASP.NET 2.0开发详解——使用C#.part05
ASP.NET 2.0开发详解——使用C#.part08ASP.NET 2.0开发详解——使用C#.part08
ASP.NET 2.0开发详解——使用C#.part07ASP.NET 2.0开发详解——使用C#.part07
ASP.NET 2.0开发详解——使用C#.part09ASP.NET 2.0开发详解——使用C#.part09
Asp.net 数据源控件是 Asp.net 框架中的一种重要组件,用于将数据绑定到 Web 应用程序中。数据源控件可以与数据库进行交互,获取数据,并将其绑定到数据绑定控件中,以实现数据的展示。下面将详细介绍 Asp.net 数据...
关于c#asp.net的数据绑定练习文档 关于c#asp.net的数据绑定练习文档 关于c#asp.net的数据绑定练习文档 关于c#asp.net的数据绑定练习文档
详细描述ASP.NET数据绑定技术,采用原理与实例结合的方法通俗易懂的介绍数据绑定技术。
3. **数据绑定**:ASP.NET支持多种数据绑定机制,如DataSource控件和Linq-to-SQL,使得数据与UI的绑定更加简单。数据绑定可以在控件级别或整个页面级别进行,方便数据展示和更新。 4. **状态管理**:ASP.NET提供了...
《圣殿祭司的ASP.NET 2.0开发详解——使用C#》是一部专注于ASP.NET 2.0技术的深入教程,特别强调了使用C#编程语言进行开发的方法。这本书籍光盘包含了丰富的资源,旨在帮助开发者全面掌握ASP.NET 2.0框架,提升Web...
在数据绑定模板中,ASP.NET控件如Label、TextBox等可以与数据源的属性通过Eval()或Bind()方法绑定。例如,<asp:Label ID="ClientIDLabel" runat="server" Text='("ClientID") %>' />将显示数据源中当前记录的...