CMS系统模板引擎设计(5):Label应用初探

从上面的方法中,我们可以看到替换的机制是每一行数据都要执行一次所有字段的替换(所以之前有提过在构造嵌套的时候为了防止Field混乱要处理TemplateString),最后返回html。我们还能看到一些未知的方法和字段:GetDataSource(),Field.Html,Field.GetValue(),这些已经暴露了我们的Field设计的部分内容。我们先看GetDataSource()是什么?

        /// <summary>        /// 获取Article列表        /// </summary>        /// <returns></returns>        private IEnumerable<Article> GetDataSource()        {             var parameter = new ArticleQueryParameter();            //构造查询的参数            return ArticleDataHelper.GetList(parameter);        }    /// <summary>    /// 查询参数基类    /// </summary>    public class QueryParameter    {        public int PageSize { get; set; }        public int PageIndex { get; set; }        public int RecordCount { get; set; }        public string SearchKey { get; set; }    }    /// <summary>    /// 文章查询类    /// </summary>    public class ArticleQueryParameter    {        public QueryParameter PageParameter { get; set; }        public DateTime PostTime { get; set; }        public int CategoryId { get; set; }        public int Top { get; set; }    }    /// <summary>    /// 文章获取数据类    /// </summary>    public class ArticleDataHelper    {        public static IEnumerable<Article> GetList(ArticleQueryParameter parameter)        {            return null;        }    }

其实就是获取ArticleList的数据源,具体的实现方式大家可能都不一样,但Article.List最终需要这么一个数据获取的方法,然而这个方法都需要接受一些查询条件的参数,这些参数都来自Parameters!!现在我们来填充GetDataSource()的参数构造部分。

      private IEnumerable<Article> GetDataSource()        {            var parameter = new ArticleQueryParameter();            //构造查询的参数            parameter.CategoryId = Parameters["CategoryId"].ConvertToInt(0);            parameter.Top = Parameters["Top"].ConvertToInt(Parameters["PageSize"].ConvertToInt(0));            var pageIndex = Parameters["PageIndex"].ConvertToInt(1);            if (pageIndex > 1)            {                parameter.PageParameter = new QueryParameter                {                    PageIndex = pageIndex,                    PageSize = parameter.Top                };            }            return ArticleDataHelper.GetList(parameter);        }

Parameters是Label的ParameterCollection,他可以通过索引直接访问具体的parameter。ConvertTo<T>(T defaultValue)是可以将parameter的value转成T类型。 这就是Parameter所用到的地方之一。另外可以看到Field具体Html属性和GetValue方法,而且GetValue接受了当前Article实体作为参数(不接受参数的话,我们怎么得到某个字段的值呢:)。

所有的List都可能会有分页,所以ListBase应该有PageParameter,所有的List都会去循环DataSoruce,所以ListBase默认实现了DataSource循环,但是增加了一个方法那就是GetDataSource。这个方法是抽象的,所有的List必须实现。


foreach里我也做了点细微的调整,就是把Field的GetValue的参数拿掉了,换成了成员,这样更明白些。你可能会有一些疑点:

为什么设计为抽象而不是虚方法或接口?

所有子类的实现方法都不一致,没有可提取部分,所以虚函数没有意义,如果单独抽象成接口,则所有子类必须继承此接口,因为GetRenderHtml和该方法紧密结合,foreach里需要显式转换为接口才能调用,完全没有意义。

为什么是GetDataSource方法,而不是公开一个DataSource成员?如果需要Set呢?还要增加一个SetDataSource?

另外一点就是为什么用了dynamic,而不是T。

首先不能是T,如果是T,则GetRenderHtml调用时也需要指明T,则整个ListBase就要变成泛型类ListBase<T>,除非base不执行GetDataSource调用。为什么不能用ListBase<T>?因为有些GetDataSource会用linq返回匿名类型集合,子类无法确定返回的具体类型名称,所以就不能继承ListBase<T>。但我们可以用dynamic,动态类型,到真正执行时可以确定T就行,这个不用我们操心,然而object显然略逊一筹了。

这样一来,Article的List只需要实现GetDataSource就行了。

这只是最简单的List雏形,假如说我还需要像Repeater控件那样,有headtemplate itemtemplate foottemplate altertemplate spacetemplate怎么办?

代码

今天就讲到这了,不知道还有朋友有兴趣没有,目前还没有演示,或许某天我会放出个demo源码。 下次讲Field的设计吧,这也算是最后一个设计了。

人的不幸缘于欲望,所以知足者长乐。

CMS系统模板引擎设计(5):Label应用初探

相关文章:

你感兴趣的文章:

标签云: