知识大全 深入ASP.NET数据绑定(上)

Posted 语法

篇首语:最淡的墨水,也胜过最强的记性。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 深入ASP.NET数据绑定(上)相关的知识,希望对你有一定的参考价值。

深入ASP.NET数据绑定(上)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  在ASP NET我们在使用Repeater DetailsView FormView GridView等数据绑定模板时 都会使用<%# Eval( 字段名 ) %>或<%# Bind( 字段名 ) %>这样的语法来单向或双向绑定数据 但是我们却很少去了解 在这些语法的背后 ASP NET究竟都做了哪些事情来方便我们使用这样的语法来绑定数据 究竟解析这样的语法是在编译时 还是运行时?如果没有深入去了解 我们肯定不得而知 这个简短的系列文章就是带我们大家一起去深入探究一下ASP NET绑定语法的内部机理 以让我们更加全面的认识和运用它

  事件的起因是 我希望动态的为Repeater控件添加行项模板 我可以通过实现ITempate接口的方式来动态添加行模板 并希望它通过普通的页面绑定语法来完成数据字段的绑定功能 如下就是一个简单的例子

   : /// <summary>

   : /// Summary description for DynamicTemplate

   : /// </summary>

   : public class DynamicTemplate : ITemplate

   :

   : public DynamicTemplate()

   :

   : //

   : // TODO: Add constructor logic here

   : //

   :

   : #region ITemplate Members

   : 

   : public void InstantiateIn(Control container)

   :

   : TextBox textBox = new TextBox();

   : textBox Text = @ <%# Eval( ID ) %> ;

   : container Controls Add(textBox);

   :

   : #endregion

   :

  在这个例子中 我在模板中添加了一个TextBox控件 并指定它的绑定字段是 ID 但是这做法 能否实现我们实现我们需要的功能呢?答案是否定 每一行的TextBox的值都是 <%# Eval( ID ) %> 而不会像我们希望的那样去绑定ID字段 从结果来分析原因 我们可以非常容易得出 这段绑定语法并没有得到ASP NET运行时的承认 那么页面中使用相同的语法为什么可以呢?故事就是从这里开始的

  我们首先要去了解下 在页面中使用这样的语法ASP NET都为我们做了哪些事情呢?要了解这个 我们要找到 aspx文件在首次运行时动态编译的程序集

  我们都知道 在ASP NET运行时 也会把 aspx文件编译成一个动态类 这个类是继承于 aspx的Page指令中Inherits属性指定的类并且同时也直接实现了IHttpHandler接口 这个动态类会负责创建页面中使用的各种服务器端控件的实例 并且ASP NET运行时会负责解析的编译 aspx中存在的服务器端代码(包括绑定语法)并将这些代码编译到这个页面类 WebSite工程和Web Application在页面文件上有些不同 WebSite工程的每个页面最多可以有两个文件 aspx和 aspx cs文件 而在Web Application还可以包括 aspx designer cs文件 这个文件所起的作用也非常有限 也就是为了能在页面代码中使用服务器端 控件实例而定义的一个实例变量 仅此而已 所以在设计时WebSite具备更多的动态行为 而在运行时WebSite工程和Web Application并没有太大区别

  如何得到页面的动态类呢?要首先得到这个页所在的动态程序集 在Vista以前的操作系统上 一般是在 %SystemRoot%\\Microsoft NET\\Framework\\v \\Temporary ASP NET Files 文件夹下 而在Vista中 而会在 %USERPROFILE%\\AppData\\Local\\Temp\\Temporary ASP NET Files下 那么如何快速得到程序集的路径和名称?你可以让你的Web工程动态编译出错(比如重复的类名) 就可以快速定位到当前动态程序集的目录了

  动态类中会有很多的内容 我们不作更多的分析 我们把目光集中绑定代码上 假设现在页面上有这么一段Repeater绑定代码

   : <asp:Repeater runat= server ID= repeater >

   : <HeaderTemplate>

   : <table>

   : <tr>

   : <td>

   : ID

   : </td>

   : <td>

   : 电流a

   : </td>

   : <td>电压(V)</td>

   : <td>

   : 备注

   : </td>

   : <td>

   : 名称]

   : </td>

   : </tr>

   : </HeaderTemplate>

   : <ItemTemplate>

   : <tr>

   : <td>

   : <%# Eval( ID )%>

   : </td>

   : <td>

   : <%# Eval( 电流a )%>

   : </td>

   : <td><%# Eval( 电压(V) )%></td>

   : <td>

   : <%# Eval( 备注 )%>

   : </td>

   : <td>

   : <%# Eval( 名称] )%>

   : </td>

   : </tr>

   : </ItemTemplate>

   : <FooterTemplate>

   : </table>

   : </FooterTemplate>

   : </asp:Repeater>

  那么在动态类中 相应的会有这样的一段函数 是用来创建ID为repeater的控件实例

   : [DebuggerNonUserCode]

   : private Repeater __BuildControlrepeater()

   :

   : Repeater repeater = new Repeater();

   : base repeater = repeater;

   : repeater HeaderTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this __BuildControl__control ));

   : repeater ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this __BuildControl__control ));

   : repeater FooterTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this __BuildControl__control ));

   : repeater ID = repeater ;

   : return repeater;

   :

   : 

   :

  CompiledTempateBuilder和BuildTemplateMethod只是模板实例化的一个中介 真正用于添加模板内容的是后面的那些私有函数 如ItemTempate的模板内容实例的创建就在__BuildControl__control 函数中 这个函数原型定义是

   : [DebuggerNonUserCode]

   : private void __BuildControl__control (Control __ctrl)

   :

   : DataBoundLiteralControl control = this __BuildControl__control ();

   : IParserAccessor accessor = __ctrl;

   : accessor AddParsedSubObject(control);

   :

   : 

  在这个函数里 调用了另一个私有函数this __BuildControl__control 这个函数返回的一个DataBoundLiteralControl对象 并将对象输出添加到__ctrl参数 事实上 只要我们去阅读CompiledTempateBuilder就发现在 这里的__ctrol对象就是我们在实例化模板时传入的对象 也就是ITemplate中的InstantiateIn方法的那个container参数对象

  为什么使用的是AddParsedSubObject方法 使用这个方法添加子控件相当于告诉父控件 这是一个已经解析好的子控件对象 不需再去将控件解析成HTML代码 而在输出时直接输出Text属性的值即可 从这里我们还可以得知DataBoundLiteralControl的对象 事实上就是承担了字符串拼接的职责 这一点我们可以在后面的分析中得以验证

  __BuildControl__control 私有函数的定义如下

   : [DebuggerNonUserCode]

   : private DataBoundLiteralControl __BuildControl__control ()

   :

   : DataBoundLiteralControl control = new DataBoundLiteralControl( );

   : control TemplateControl = this;

   : control SetStaticString( \\r\\n <tr>\\r\\n <td>\\r\\n );

   : control SetStaticString( \\r\\n </td>\\r\\n <td>\\r\\n );

   : control SetStaticString( \\r\\n </td>\\r\\n \\r\\n <td>\\r\\n );

   : control SetStaticString( \\r\\n </td>\\r\\n <td>\\r\\n );

   : control SetStaticString( \\r\\n </td>\\r\\n </tr>\\r\\n );

   : control DataBinding += new EventHandler(this __DataBind__control );

   : return control;

   :

  在这个函数里面 创建了一个DataBoundLiteralControl对象 并将页面上定义的模板的静态HTML代码添加到该的静态字符串数组里 并且设置了它的绑定事件代理函数__DataBind__control 该函数的定义

   : public void __DataBind__control (object sender EventArgs e)

   :

   : DataBoundLiteralControl control = (DataBoundLiteralControl) sender;

   : RepeaterItem bindingContainer = (RepeaterItem) control BindingContainer;

   : control SetDataBoundString( Convert ToString(base Eval( ID ) CultureInfo CurrentCulture));

   : control SetDataBoundString( Convert ToString(base Eval( 电流a ) CultureInfo CurrentCulture));

   : control SetDataBoundString( Convert ToString(base Eval( 备注 ) CultureInfo CurrentCulture));

   : control SetDataBoundString( Convert ToString(base Eval( 名称] ) CultureInfo CurrentCulture));

   :

  在这个函数中 我们看到了真正的数据绑定代码了 它调用了TemplateControl的Eval方法来将当前数据项的相应字段的值取出 并按一定的格式转化后添加到DataBoundLitreralControl对象中 并在DataBoundLiteralControl将StaticString和DataBoundString字符串数组按一定的顺序拼接起来 作为Text属性的输出值 而容器控件则直接向客户端输这段HTML

  下面 我们还有必要来分析下TemplateControl中的Eval方法 这个方法有两种重载 简单起见 我们来分析较为简单的重载

   : protected internal object Eval(string expression)

   :

   : this CheckPageExists();

   : return DataBinder Eval(this Page GetDataItem() expression);

   :

  这个方法 使用了DataBinder Eval静态方法来得到绑定表达式(字段名)的值 它的数据是通过this Page GetDataItem()这样的一个方法得到的 那么为什么this Page GetDataItem()就可以得到当前正在被绑定的数据项呢?原来 在页面绑定数据时 它会有一个堆栈来保存它所有的绑定控件绑定时用到的数据项 我们只需要取得堆栈顶部的那个元素 就可以在页面的作用域内的任何一个位置得到当前正在被绑定的数据项 如上的例子 我们就可以取得当前绑定的RepeaterItem的DataItem的数据项 因此我们不需要与RepeaterItem有任何的联系

  如果硬要用上面的代码来描述数据绑定的全过程 跨度过大 但是有了以上的分析 我们再用文字的形式再来总结下 应该就会一个比较完整的印象了 在ASP NET的数据模板控件中 可以使用<%# %>这样的语法来将字段值作为一个占位符 用在HTML代码中 可以方便我们设计和生成最终的HTML代码 不需要很多的字符拼接工作 而ASP NET运行时在首次执行页面时 会为页面编译一个动态类 在这个动态类中会实例化所有的服务器端控件 编译和解析绑据模板控件的绑定语法 并用一些对象和操作来完成数据绑定的字符串接拼接行为 因此绑定语法的解析事实上是编译时的行为 只不过这个编译时是延迟到页面的首次执行时 这就可以解释为什么在我们想在动态添加模板中使用<%# %>这样的绑定语法时 无法解析的原因

  而对于DataBinder Eval方法 这是ASP NET提供的一个数据绑定辅助方法 通过这个方法 我们可以方便的从种不同的数据项 如自定义对象或DataRow取出对象的字段(属性值) 从而为我们屏蔽很多不必要的数据来源类型的判断 同时DataBinder这个类还提供了其它的绑定辅助方法 大家可以从MSDN查看更多有用的帮助

来实现数据双向绑定的机理 cha138/Article/program/ASP/201311/21681

相关参考

知识大全 ASP.NET之数据绑定2

ASP.NET之数据绑定2  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  &

知识大全 ASP.NET数据绑定控件比较浅析

ASP.NET数据绑定控件比较浅析  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  ASPNET数

知识大全 asp.net 数据绑定的实例代码

这篇文章介绍了aspnet数据绑定的实例代码有需要的朋友可以参考一下 复制代码代码如下:cha138/Article/program/net/201311/14140

知识大全 ASP.NET 2.0高级数据处理之数据绑定

ASP.NET2.0高级数据处理之数据绑定  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!在前面的模

知识大全 ASP.NET入门教程 7.4 数据绑定控件

ASP.NET入门教程7.4数据绑定控件  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 

知识大全 asp.net Repeater 数据绑定的具体实现

asp.netRepeater数据绑定的具体实现  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  

知识大全 ASP.NET入门教程 7.2.2 数据绑定控件[2]

ASP.NET入门教程7.2.2数据绑定控件[2]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&

知识大全 ASP.NET入门教程 7.2.2 数据绑定控件[1]

ASP.NET入门教程7.2.2数据绑定控件[1]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&

知识大全 ASP.NET入门教程 7.2.2 数据绑定控件[3]

ASP.NET入门教程7.2.2数据绑定控件[3]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&

知识大全 ASP.NET 2.0中实现模板中的数据绑定

ASP.NET2.0中实现模板中的数据绑定  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  模板化