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

 

转载于:https://www.cnblogs.com/lekko/archive/2013/05/18/3046481.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值