zoukankan      html  css  js  c++  java
  • ASP.NET中使用ListView多层绑定的分页问题始末

      前段时间着手做一个网站,在使用ListView和DataPager时遇到了一个新问题。先描述一下页面的要求吧:有两级类别,一个大类,下面有子类,子类下才对应了产品,然后在一个页面中把大类(指定了哪些)、子类、产品按结构显示出来,其中产品要有分页。好了,目前来说,整个页面交互性只在于产品的分页上,大类、子类在服务器端只是显示的作用,故我理所当然地想到了使用ListView来层层绑定,并在产品层添加DataPager控件来分页。

      后台的数据DTO也已经定义好,分别有大类、小类、产品:

     1     // 产品大类DTO
     2     public class ProductTypeDTO
     3     {
     4         public int ID { get; set; }
     5         // ...
     6         public IEnumerable<CategoryDTO> Categorys { get; set; }
     7     }
     8 
     9     // 产品小类DTO
    10     public class CategoryDTO
    11     {
    12         // ...
    13         public IEnumerable<ProductDTO> Products { get; set; }
    14     }
    15 
    16     // 产品DTO
    17     public class ProductDTO
    18     {
    19         public int ID { get; set; }
    20         // ...
    21     }

      以惯性思维,先把大类数据源传给第一层ListView,再在一层内写小类ListView,最后再在小类ListView中写产品与DataPager。目前假设已经处理完成的数据源为IList<ProductTypeDTO> ProductTypeList,它就是我们要显示的东西了。

      最初设计的前台代码为:

     1              <!-- Begin Types -->
     2              <asp:ListView ID="LV_Products" runat="server">
     3                  <ItemTemplate>
     4                      // 这里是大类需要解析的HTML控件           
     5                      <!-- Begin Categorys-->
     6                      <asp:ListView DataSource='<%# DataBinder.Eval(Container.DataItem,"Categorys") %>' runat="server">
     7                          <ItemTemplate>
     8                                      // 这里是小类需要解析的HTML控件                                              
     9                                      <!-- Begin Products -->
    10                                      <asp:ListView ID="LV_Item" DataSource='<%# DataBinder.Eval(Container.DataItem,"Products") %>' runat="server">
    11                                          <ItemTemplate>
    12                                              // 这是具体产品需要解析的HTML控件                                            
    13                                          </ItemTemplate>
    14                                      </asp:ListView>
    15                                      <!-- End Products-->
    16                                      <div class="cleardiv"></div>
    17                                      <!-- Begin DataPager-->
    18                                      <div class="product_dp">
    19                                          <asp:DataPager ID="DP_Item" PageSize="10" PagedControlID="LV_Item" runat="server">
    20                                              <Fields>
    21                                                  // 这是分页按钮
    22                                              </Fields>
    23                                          </asp:DataPager>
    24                                      </div>
    25                                      <!-- End DataPager-->                                
    26                              <div class="cleardiv"></div>
    27                              <br />
    28                          </ItemTemplate>
    29                      </asp:ListView>
    30                      <!-- End Categorys-->
    31                      <div class="cleardiv"></div>
    32                      <br />
    33                  </ItemTemplate>
    34              </asp:ListView>
    35              <!-- End Types -->

      以上省略了与问题无关的一些绑定项代码,根据以往的经验,要想不出现点击两次才翻页的情况,可以把数据绑定语句:

      LV_Products.DataSource = ProductTypeList;
      LV_Products.DataBind();

      写在Page_PreRender中,在IIS中调试一看,唔,数据正常显示,分页已经分好,但是我一点其它页的,完全没作用,页面闪了一下,页面的元素还是第一页那些。经过排查,我觉得是数据绑定的问题(在PreRender中进行绑定,会导致每次都进行了一次数据更新,而我的LV_Item是动态生成的,DataPager也是动态的,这会导致生成一个全新的页面,而不会根据以前的PageIndex生成翻页),于是把后台绑定的代码改成写在!IsPost中,看了下,能分页、能显示,点击分页,好像是发生了跳转,可惜那些数据不能正常地绑定进来,而且需要点击2次才能正常跳转。

      思来想去,还是对ASP.NET的页面加载不了解,于是仔细看了它的初始化流程,觉得与Page_PreRender相似的,我使用ListView.PreRender事件应该也可以达到相同效果,那么需要取消LV_Item的绑定,而在后台手动来绑定其数据源(LV_Products的绑定放在!IsPostBack内)。当页面第一次加载时就绑定所有LV_Item的数据,当分页回传时,只重新绑定对应的LV_Item的数据源。LV_Item的前台代码改为:

    <asp:ListView ID="LV_Item" OnPagePropertiesChanged="LV_PageChanged" runat="server">
        // ...
    </asp:ListView>

      看到了没,就是通过ListView的分页改变事件来触发数据源绑定的,绑定需要发生在它的PreRender事件中:

    protected void LV_PageChanged(object sender, EventArgs e)
    {
        (sender as ListView).PreRender += LV_OnPreRender;
    }

      这下明白了吧,第一次加载页面,所有的ListView都会自动触发OnPagePropertiesChanged事件,于是所有的ListView都会加载PreRender事件处理函数进行数据绑定,而当点击分页回传里,只有一个ListView会触发OnPagePropertiesChanged事件,也就只有一个ListView会加载PreRender事件处理函数,所以绑定源的重新绑定将只发生一个LV_Item身上。

      好了,LV_OnPreRender作为LV_Item的重新绑定函数,需要有具体的大类、小类的信息才能把产品列表绑定给ListView,目前我只有一个ProductTypeList把大类、小类、产品的关系给封装好了,而LV_OnPreRender、LV_PageChanged都不能得到目前这个ListView是哪个大类下的哪个小类的列表信息,怎么办?

      只好另辟蹊径了,来看个LV_Item生成的客户端代码:

      发现了什么,这个是有命名规则的!CPH_main是我用的母版名,LV_Products是我的大类ListView,然后ctl100,它是我的小类ListView(没给它命名,自动生成的),然后后面的0,就是第0个大类!再又接了个ctl100是我用的ajax UpdataPanel(本文中没有,这是实际项目中用的),后面的0、1、2、3...就是实际的小类了!唔,经过测试,这是完全没有问题的,只要你没有改ClientIDMode。在后台代码中,我们可以通过ListView.UniqueID来获取与这类似的值,只是有一点区别。于是我们最后一个要点LV_OnPreRender的函数为:

     1     private static Regex _productRegex = new Regex(@"(?<=ctrl)\d+", RegexOptions.Singleline);
     2     // 绑定数据源
     3     protected void LV_OnPreRender(object sender, EventArgs e)
     4     {        
     5         var lv = sender as ListView;
     6         // 确认数据源
     7         /* 根据具体情况来,我的UnitqueID是这样的:
     8          * 全局标识 ctl00$CPH_main$LV_Products$ctrl0$ctl00$ctrl0$LV_Item
     9          *                                     大类        小类                       
    10         */
    11         var matche = _productRegex.Match(lv.UniqueID, 25);
    12         // 重新绑定数据
    13         try
    14         {
    15             int categoryID = Int32.Parse(matche.NextMatch().Value);
    16             int typeID = Int32.Parse(matche.Value);
    17             lv.DataSource = BaseConfig.ProductTypeList[typeID].Categorys.ElementAt(categoryID).Products;
    18             lv.DataBind();
    19         }
    20         catch
    21         {
    22             // 错误处理
    23         }
    24     }

      至此,分页完成,效率不错,在IIS上测试起来非常快,百来条一下的事。想看最终效果图的,可以点我打开图片链接。

      转载请注明原址:http://www.cnblogs.com/lekko/archive/2013/04/27/3046481.html

  • 相关阅读:
    EXTJS 4.2 资料 控件之checkboxgroup的用法(静态数据)
    EXTJS 4.2 资料 控件之Window窗体相关属性的用法
    EXTJS 4.2 资料 控件之textfield文本框加事件的用法
    Entity Framework 学习笔记(一)之数据模型 数据库
    EXTJS 4.2 资料 控件之checkboxgroup的用法(动态数据)
    EXTJS 4.2 资料 控件之Grid 列鼠标悬停提示
    Entity Framework 学习笔记(二)之数据模型 Model 使用过程
    EXTJS 4.2 资料 控件之radiogroup 的用法
    EXTJS API
    vue移动端弹框组件,vue-layer-mobile
  • 原文地址:https://www.cnblogs.com/lekko/p/3046481.html
Copyright © 2011-2022 走看看