5,VTemplate模板引擎的使用--高级篇
原文地址:https://www.cnblogs.com/kingthy/archive/2009/09/04/net-vtemplate-doc-4.html
在网站中,经常会有某个栏目的数据在多个页面同时使用到。比如新闻网站或电子商务网站的栏目列表,几乎在很多页面都会显示栏目导航。对于这种多个页面同时使用到的“数据区”在ASP.NET Web Form开发中,经常会将这些“数据区”独立封装为一个个Web控件。那在VTemplate模板引擎里又要如何做呢?在VTemplate模板引擎里,提供了一种“模板块解析器”接口。当VTemplate模板引擎解析并呈现VT模板数据时,如果发现某个<vt:template>标签已定义“模板块解析器”,则会构建此“模板块解析器”实例并将解析权交给“模板块解析器”,等其处理完后再继续解析呈现标签数据。其流程图如下:
在<vt:template>标签使用“模板块解析器”,是利用其已定义的两个特殊属性:
名称 | 说明 |
render | 定义用于处理此模块数据的实例,格式:"类实例,程序集"。如果已定义此属性但未定义rendermethod属性,则类实例必须已实现ITemplateRender接口。(可不定义) |
rendermethod | 定义用于处理此模块数据的类实例的方法,此方法必须已标记TemplateRenderMethodAttribute特性。(可不定义) |
如果是使用ITemplateRender接口来实现“模板块解析器”,则只需要定义render属性;如果用TemplateRenderMethodAttribute特性来实现“模板块解析器”,则必须要定义render和rendermethod方法!
注意:TemplateRenderMethodAttribute特性的优先权最高,即如果同时定义了这两个属性,则不管render定义的类是否已实现ITemplateRender接口都会被忽略不用,而直接使用rendermethod定义的特性方法!
1、ITemplateRender接口。
/// <summary>
/// 模板块数据的解析处理接口
/// </summary>
public interface ITemplateRender
{
/// <summary>
/// 预处理解析模板数据
/// </summary>
/// <param name="template"></param>
void PreRender(Template template);
}从上可知,ITemplateRender接口只有一个声明方法PreRender,用于接收处理VTemplate模板引擎转交过来要进行解析的模板块。
我们将《VTemplate模板引擎的使用--进阶篇》的最后一个例子改一下,用ITemplateRender接口来处理那些新闻列表数据。
我们先构建一个已实现ITemplateRender接口的类,代码如下:
namespace VTemplate.WebTester.Core { /// <summary> /// 模板块解析器 /// </summary> public class CnblogsNewsRender : ITemplateRender { #region ITemplateRender 成员 /// <summary> /// 解析某个模板块的数据 /// </summary> /// <param name="template"></param> public void PreRender(Template template) { //根据模板块里定义的type属性条件取得新闻数据 List<News> newsData = NewsDbProvider.GetNewsData(template.Attributes.GetValue("type")); //设置变量newsdata的值 template.Variables.SetValue("newsdata", newsData); //取得模板块下Id为newslist的标签(也即是在cnblogs_newsdata.html文件中定义的foreach标签) Tag tag = template.GetChildTagById("newslist"); if (tag is ForEachTag) { //如果标签为foreach标签则设置其BeforeRender事件用于设置变量表达式{$:#.news.url}的值 tag.BeforeRender += (sender, e) => { ForEachTag t = (ForEachTag)sender; //取得当前项的值(因为foreach标签的数据源是List<News>集合,所以当前项的值类型为News实体) News news = (News)t.Item.Value; //设置当前项的变量表达式的值.也即是"{$:#.news.url}"变量表达式 t.Item.SetExpValue("url", NewsDbProvider.GetNewsUrl(news)); //当新闻不可见时.你可以取消本次输出 if (!news.Visible) e.Cancel = true; }; } } #endregion } }这样我们就构造了一个“模板块解析器”,在VT模板里就可以直接使用了,如下:
<div class="side_block">
<h3 class="title_blue">相关新闻</h3>
<vt:template name="topnews" type="relating" file="cnblogs_newsdata.html" render="VTemplate.WebTester.Core.CnblogsNewsRender,VTemplate.WebTester" />
</div>
<div class="side_block">
<h3 class="title_yellow">热点新闻</h3>
<vt:template name="topnews" type="hoting" file="cnblogs_newsdata.html" render="VTemplate.WebTester.Core.CnblogsNewsRender,VTemplate.WebTester" />
</div>具体的示例代码,请参考:http://net-vtemplate.googlecode.com/svn/src/VTemplate.WebTester/templaterender_test.ashx.cs
2、TemplateRenderMethodAttribute特性方法
TemplateRenderMethodAttribute特性方法的原形和ITemplateRender接口的PreRender差不多,即只能有一个参数,用于接收VTemplate模板引擎转交过来要进行解析的模板块对象。如下面例子代码:
/// <summary> /// 解析某个模板块的数据 /// </summary> /// <param name="template"></param> [TemplateRenderMethod(Description="解析新闻列表数据")] public void RenderNews(Template template) {}而VT模板代码就需要定义<vt:template>的rendermethod属性,并且定义的值必须和类代码中的方法名一致,如下面例子代码:
<div class="side_block">
<h3 class="title_blue">相关新闻</h3>
<vt:template name="topnews" type="relating" file="cnblogs_newsdata.html" render="VTemplate.WebTester.Core.CnblogsNewsRenderMethod,VTemplate.WebTester" rendermethod="RenderNews" />
</div>
<div class="side_block">
<h3 class="title_yellow">热点新闻</h3>
<vt:template name="topnews" type="hoting" file="cnblogs_newsdata.html" render="VTemplate.WebTester.Core.CnblogsNewsRenderMethod,VTemplate.WebTester" rendermethod="RenderNews" />
</div>
具体的示例代码,请参考:http://net-vtemplate.googlecode.com/svn/src/VTemplate.WebTester/templaterendermethod_test.ashx.cs
TemplateRenderMethodAttribute特性方法与ITemplateRender接口比较,它的好处就是可在一个类实例中定义多个方法用于处理不同的模板块,也即是说可在一个类实例里定义多个“模板块解析器”。