给Repeater的数据绑定添加智能感知

    在项目中,Repeater是使用频度比较高的控件, 一方面它结构简单,速度较快, 同时我们也想办法让它工作得更好, 前不久写过关于数据绑定的东西, 使用Eval方法呢,虽然简单,但是性能不怎么好, 可以将数据项转成 DataRowView 或者是强类型的DTO, 但是写起来不够简洁. 今天在研究netTiers 生成的代码的时候,发现了这个有意思的应用,强类型的好处就不用说了,可以在编译时发现拼写错误了,会节省我们不少的时间,同时通过对"Repeater"的扩展我们可以方便地实现一些其它的特性,好了,我们就用一个实例来说明. 在这个示例中,我们需要绑定一个List<Article>的实体集合列表到控件上面, 先看看效果图:

在这里,我们只要输入一个Container,后面就会自动出现Article的属性了, 是不是很方便啊,不用Hardcode实体属性了.

需要说明的是,这里的ArticleRepeater并不是一个"真正"的Repeater, 它是从Control继承过来的, 因为有时候我们并不需要很多的特性,可以使用这样的简化版的控件 (  俺对性能的要求是不是太严格了点~~;(  ),  还可以借机学习一下控件开发的相关知识. 下面是这个控件的代码:本来还应该有一些设计时的代码内容以方便给那些DragDropCoder,在这里就省略了,“界面在心中”~~~;)
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.ComponentModel;

namespace Demo.Web
{
    [ParseChildren(
true)]//这里加这个特性很重要,否则.net将不会识别在前台的模版里面书写的内容.
    public class AticleRepeater : Control, INamingContainer//我们并没有从Repeater继承出来.
    {
        
Public properties

        
private ITemplate bodyTemplate;

        
public AticleRepeater()
        
{
        }


        [Browsable(
false)]
        [TemplateContainer(
typeof(ArticleDataItem))]
        [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
        
public ITemplate MyBodyTemplate//如何申明一个模版.
        {
            
get return bodyTemplate; }
            
set { bodyTemplate = value; }
        }


        
protected override void OnPreRender(EventArgs e)
        
{
            
base.DataBind();//这个也是必须的~~否则不能执行<%# Container.DataItem %> 内容.
        }


        
protected override void CreateChildControls()
        
{
            
if (ChildControlsCreated)
            
{
                
return;
            }

            Controls.Clear();

            
if (bodyTemplate != null)
            
{
                
int indexer = 1;
                
foreach (Article _article in dataSource)
                
{
                    ArticleDataItem item 
= new ArticleDataItem(_article);
                    
if (titleDisplayLength != -1)
                        item.DisplayWordCount 
= titleDisplayLength;

                    
if (hilightCount != -1)
                    
{
                        
if (indexer <= hilightCount)
                            item.ItemIndex 
= indexer;
                        
else
                            item.ItemIndex 
= 0;
                    }


                    bodyTemplate.InstantiateIn(item);
//填充构造一个可重复项目的模版并输出到控件集合.
                    Controls.Add(item);
                    indexer
++;
                }

            }

            ChildControlsCreated 
= true;//已经创建控件. 
        }


        
public override ControlCollection Controls//不可缺少.
        {
            
get
            
{
                
this.EnsureChildControls();
                
return base.Controls;
            }

        }

    }

    
/// <summary>
    
/// 这个是前台绑定时对实体类的包装, 用于实现一些高级特性, 如标题长度截取等. 您可以自行扩展.
    
/// </summary>

    [System.ComponentModel.ToolboxItem(false)]
    
public class ArticleDataItem : System.Web.UI.Control, System.Web.UI.INamingContainer
    
{
        
private Article m_article = new Article();

        
public ArticleDataItem(Article article)
        
{
            
this.m_article = article;
        }


        [Bindable(
true)]//这个特性让我们在前台可以自动感知.
        
public string Title
        
{
            
//如果需要截短标题.
            get
            
{
                
if (displayWordCount != -1)
                    
return m_article.Title.Substring(0, displayWordCount);
                
else
                    
return m_article.Title;
            }

        }


        [Bindable(
true)]
        
public string AuthorName
        
{
            
get return m_article.AuthorName; }
        }


        [Bindable(
true)]
        
public int AuthorID
        
{
            
get return m_article.AuthorID; }
        }


        [Bindable(
true)]
        
public int ClickCount
        
{
            
get return m_article.ClickCount; }
        }


        
private int displayWordCount = -1;
        
/// <summary>
        
/// 显示字数, 超过这个值的将被截断.
        
/// </summary>

        public int DisplayWordCount
        
{
            
get return displayWordCount; }
            
set { displayWordCount = value; }
        }


        
private int itemIndex;
        
/// <summary>
        
/// 是第几条数据.
        
/// </summary>

        public int ItemIndex
        
{
            
get return itemIndex; }
            
set { itemIndex = value; }
        }

    }

}


在这里我们实现两个扩展功能,一个是截取标题的长度,一个是将前N条高亮显示,可以直接通过属性声明的方式添加即可, 俺在这里抛砖引玉,大家可以发挥创造力添加其它有用的特性。

代码里面有比较详细的注释,我就不再做说明. 对于重复性的代码,您可以开发相应的CodeSmith模版来快速成生成.

我们再来看一下前台的代码写法都有些什么不同.

        <h1>
            下面这种是原始的写法,虽然可以达到效果,但是比较麻烦.
</h1>
        
<ul>
            
<asp:Repeater runat="server" ID="rpOrigin">
                
<ItemTemplate>
                    
<li>[点击:
                        
<%# Eval("ClickCount"%>]
                        
<%# GetShortString(Eval("Title").ToString(), 10%>___Post by
                        
<%# Eval("AuthorName"%></li>
                
</ItemTemplate>
            
</asp:Repeater>
        
</ul>
        
<h1>
            添加了前N条高亮的功能.
</h1>
        
<ul>
            
<CnBlogs:AticleRepeater runat="server" ID="rpArticles" HilightCount="3">
                
<%--前面3条高亮--%>
                
<MyBodyTemplate>
                    
<li class='list_<%# Container.ItemIndex %>'>[点击 :
                        
<%# Container.ClickCount %>]
                        
<%# Container.Title %>___Post by
                        
<%# Container.AuthorName %></li>
                
</MyBodyTemplate>
            
</CnBlogs:AticleRepeater>
        
</ul>
        
<h1>
            截短标题的列表, 只显示10个字符.
        
</h1>
        
<ul>
            
<CnBlogs:AticleRepeater runat="server" ID="rpArticle2" TitleDisplayLength="10">
                
<%--最多显示10个字符--%>
                
<MyBodyTemplate>
                    
<li>[点击 :
                        
<%# Container.ClickCount %>]
                        
<%# Container.Title %>___Post by
                        
<%# Container.AuthorName %></li>
                
</MyBodyTemplate>
            
</CnBlogs:AticleRepeater>
        
</ul>

高亮效果图:

 完整的代码示例请在此处下载,  俺用的是Vs2008 / .net 2.0(在沙加的神舟本上), 使用VS2005的同学重新建一个自己的解决方案将两个工程添进来即可.

有人也许会问如果绑定的是DataTable或者DataReader怎么办? 可在包装类里面稍作改造也就是我们这里ArticleDataItem,就留给同学习们自己去研究吧;)

posted on 2008-02-03 16:49  沙加  阅读(6304)  评论(15编辑  收藏  举报

导航