• [转]ASP.NET数据绑定方法


    如何在数据绑定中写判断条件的表达式
       <%#   DataBinder.Eval(Container.DataItem,   "sex").ToString()=="1"   ?   '先生'   :   '女士'%>
    本节涉及的内容如下:
    1,数据绑定方法的来源以及在低层上的实现。
    2,数据绑定方法的执行效率排序。
    <%#Container.DataItem%>
    <%#GetDataItem()%>
    <%#Eval("字段名")%>
    <%#DataBinder.Eval(Container.DataItem,"字段名")%>
    <%#((DataRowView)Container.DataItem)["字段名"] %>
    <%#((Type)Container.DataItem).成员 %>
    <%#((Type)GetDataItem()).成员 %>
    上面七种绑定形式以及它们的变幻形式都用过吗?性能怎么排序?
    复习一下:第一节我们主要谈了数据绑定表达式的各种形式,在ASP.NET页面中出现的位置,以及我们常绑定到与数据库有关的DataView,DataTable,DataSet 等数据源的数据绑定表达式的各种形式。
    你有没有对Eval方法和DataBinder.Eval方法好奇过?
    在.NET2.0中我们经常用Eval方法在Repeater,DataList,GridView等循环控件中绑定数据,Eval方法和DataBinder.Eval方法在低层是怎么实现的?它们到底有什么千丝万缕的关系?
    一,来源、实现。
    我们常用的Eval方法其实是Page类的一个静态单向只读方法,而且它是一个受保护的方法。实际上Page类的Eval方法是继承自 TemplateControl类的。TemplateControl 类是一个抽象类,它为Page 类和 UserControl 类提供通用属性和方法。我们先来看一下继承家谱:
    System.Object
       System.Web.UI.Control
        System.Web.UI.TemplateControl
           System.Web.UI.Page
           System.Web.UI.UserControl
    Eval方法就是TemplateControl类的方法,它有两种形式:

    名称
    说明

    TemplateControl.Eval (String)
    计算数据绑定表达式。

    TemplateControl.Eval (String, String)
    使用用于显示结果的指定格式字符串计算数据绑定表达式。

    事实上TemplateControl类还提供了XPath方法和XPathSelect方法供Page类和UserControl继承。这2个方法是和XML数据源有关的绑定方法。
    如果细心的你查看TemplateControl类的基类Control类,你就会发现其实Control类并没有提供Eval,XPath,XPathSelect等方法。所以Eval,XPath等方法最终是在TemplateControl类中实现的。
    现在,终于找到了Eval,XPath等数据绑定方法的来源了。
    Eval,XPath等方法是.NET 2.0新增的方法。在.NET 1.1时代我们经常用的是DateBinder.Eval方法。形如:
    <%#DataBind.Eval(Container.DataItem,"字段名") %>
    <%#DataBind.Eval(Container.DataItem,"字段名","{0:c}") %>
    Eval的出现其实就是为了简化DataBinder.Eval方法的写法从而代替它。
    在ASP.NET 2.0中及以上,当我们调用Eval时,Eval 方法会使用GetDataItem方法调用DataBinder.Eval方法计算表达式的值。要想理解这句话,就算查边MSDN也一头雾水,除非我们知道Eval方法的源代码,否则根本找不到蛛丝马迹。这里就要用到反射了。我们通过反射获得了Eval方法的源代码:
    protected
    internal
    object   Eval(string   expression)  
      {  
    this.CheckPageExists();  
    return   DataBinder.Eval(this.Page.GetDataItem(),   expression);  
      }  
    终于见到GetDataItem()方法了,其实它就是Page类的一个方法,也是.NET 2.0新增一个方法。GetDataItem()方法的作用是为了获得Container.DataItem,它是.NET 2.0中用来代替Container.DataItem的,如果你曾经用Repeater和DataList等绑定过数组或者ArrayList等,你就会发现<%#GetDataItem()%>和<%#Container.DataItem%>等价。同时,可以肯定:Eval方法在低层上确实是调用DataBinder.Eval方法实现数据绑定的。其中“this.CheckPageExists();” 是检查调用的时候有没有Page对象的,如果没有则会抛出一个异常。
    要弄清Eval是怎么工作的,GetDataItem()方法的低层实现我们也要用反射来获取:
    public
    object GetDataItem()
        {
    if ((this._dataBindingContext ==
    null) || (this._dataBindingContext.Count ==
    0))
            {
    throw
    new InvalidOperationException(SR.GetString("Page_MissingDataBindingContext"));
            }
    return
    this._dataBindingContext.Peek();
        }  
    我们从GatDataItem()方法中看到“return   this._dataBindingContext.Peek();”很快就猜想_dataBindingContext是不是一个堆栈呢?事实它就是一个堆栈!通过反射查看源代码我们得出:_dataBindingContext是一个Stack类型对象。所以它有Peek方法。“return   this._dataBindingContext.Peek(); ”正是把堆栈顶部的元素返回。而if语句是用来判断这个堆栈是否已经存在或者是否已经有元素存在,如果if不成立,就会抛出一个异常。
    从上面的分析我们知道:_dataBindingContext堆栈的作用是通过GetDataItem()方法这个桥梁向Eval方法提供Container.DateItem。用逆向思维来理解上面这句话:Eval方法可以自动计算出Container.DataItem,原因就是从dataBindingContext 堆栈来获取Container.DataItem;这也就为什么Eval方法能够知道形如<%#Eval"字段名"%>中字段名隶属于哪个数据项的属性的原因;同时我们也知道.NET 2.0中的Eval在本质上的实现并没有抛弃Container.DataItem,而Container.DataItem在2.0时代也没有消失。
    那么_dataBindingContext这个保存Container.DataItem的堆栈是怎么建立的呢?
    我们很快就想到每次绑定控件时候最后那条语句是什么:this.控件ID.DataBind();对就是DataBind()方法,DataBind()方法还有一个重载ataBind(bool raiseOnDataBinding)。为_dataBindingContext这个堆栈压入元素和弹出元素的方法正是用DataBind(bool flag)这个重载方法实现的。
    DataBind(bool raiseOnDataBinding)在低层的实现:
    protected
    virtual
    void DataBind(bool raiseOnDataBinding)
        {
    bool flag1 =
    false;//这个标志的用处在上下文中很容易推出来,如果有DataItem压栈,则在后面出栈。  
    if (this.IsBindingContainer)//判断控件是不是数据绑定容器,实际上就是判断控件类是不是实现了INamingContainer  
            {
    bool flag2;
    object obj1 = DataBinder.GetDataItem(this, out   flag2);//这个方法是判断控件是不是有DataItem属性,并把它取出来。  
    if (flag2 && (this.Page !=
    null))//如果控件有DataItem  
                {
    this.Page.PushDataBindingContext(obj1);//把DataItem压栈,PushDataBindingContext就是调用_dataBindingContext的Push方法  
                    flag1 =
    true;
                }
            }
    try
            {
    if (raiseOnDataBinding)//这里是判断是不是触发DataBinding事件的。  
                {
    this.OnDataBinding(EventArgs.Empty);
                }
    this.DataBindChildren();//对子控件进行数据绑定,如果这个控件有DataItem,则上面会将DataItem压入栈顶,这样,在子控件里面调用Eval或者GetDataItem方法,就会把刚刚压进去的DataItem给取出来。  
            }
    finally
            {
    if (flag1)//如果刚才有压栈,则现在弹出来。  
                {
    this.Page.PopDataBindingContext();//PopDataBindingContext就是调用_dataBindingContext的Pop方法  
                }
            }
        }  
    当我们执行到this.控件ID.DataBind();时候。在低层上就会调用这个重载的方法来准备包含DataItem的_DatBindingContext堆栈。
    上面的代码中提到了DataBinding事件,那么它一般什么时候被触发呢?
    1,如果用编程方式,那么在我们调用DataBind()方法时候自动触发DataBinding事件。
    2,如果我们用数据源控件(例如SqlDataSource等),当把控件绑定到数据源控件时候,这个事件就会自动触发。
    一般数据绑定表达式常常放在模板中循环显示数据,例如Repeater和DataList等的模板。那么下面这个知识点应该知道:Repeater,DataList,FormView等控件必须使用模板,如果不使用模板,这些控件将无法显示数据。而GridView,DetailsView,Menu等控件也支持模板,但显示数据时不是必须的。而TreeView控件不支持模板。
    注意:一般情况下,数据绑定表达式不会自动计算它的值,除非它所在的页或者控件显示调用DataBind()方法。DataBind()方法能够将数据源绑定到被调用的服务器控件及其所有子控件,同时分析并计算数据绑定表达式的值。
    终于写的有点眉目了,好累!我们该回头看看Eval方法调用的静态DataBinder.Eval方法在低层的实现了。

     

    来源网站:http://blog.csai.cn/user1/14586/archives/2011/45955.html

  • 相关阅读:
    android一个纠结的VFY错误
    icon在线编辑和查找工具
    增加Android可用内存
    android对大图片的缓存处理
    MySQL sql语句大全
    Canvas
    Docker 微服务教程
    Docker 入门教程
    项目管理
    JavaScript standard 代码规范的全文
  • 原文地址:https://www.cnblogs.com/seapub/p/2574159.html
Copyright © 2020-2023  润新知