• 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

  • 相关阅读:
    H5中获取图片中的主色调
    vue provide/inject响应式
    微信小程序入坑之路
    H5入坑之路
    uni-app状态栏相关问题
    uni-app使用iconfont相关
    uni-app入坑之路
    uni-app自定义导航栏(搜索框和按钮)
    浅析浏览器的渲染过程
    SAP ABAP MB51新增栏位字段
  • 原文地址:https://www.cnblogs.com/lekko/p/3046481.html
Copyright © 2020-2023  润新知