因为公司业务需要,经过本人几个月尝试,使用Orchard CMS 开发一个简单的企业门户(地址是http://www.ubof.cn)。在刚开始接触Orchard CMS,对于个性化的网页布局不知道怎么定义,通过google的帮助终于找到比较符合Orchard的二次开发方法的解决方案,就是在Theme定义布局Widgets Layout。需要注意的是,因为要在Theme写C#代码,所以要用Orchard 命令提示创建Theme的解决方案(命令:codegen theme <theme-name> /CreateProject:true)。

当Theme的解决方案方案建立好后我们就可以开始定义自己的Widgets Layout,在这里我以自己网站上首页的一个产品展示Widgets为例子说明(此为新开发没有同步到发布站点),最后实现好的效果如下:

下面开始介绍代码的编写,第一步需要在刚建好的Theme的解决方案里,新建名称为Providers的文件夹,第二步在建好Providers文件里新建ProductsListLayoutForms的类,它必须实现Orchard里的 IFormProvider 接口,这个类主要作用是为Widgets 中HTML DOM的Id,class 提供配置表单,为以后修改class和id提供方便,具体代码如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using Orchard.DisplayManagement;
  6. using Orchard.Forms.Services;
  7. using Orchard.Localization;
  8.  
  9. namespace UBOfficeTheme.Providers.Layouts
  10. {
  11. public class ProductsListLayoutForms : IFormProvider
  12. {
  13. protected dynamic Shape { get; set; }
  14. public Localizer T { get; set; }
  15.  
  16. public ProductsListLayoutForms(IShapeFactory shapeFactory)
  17. {
  18. Shape = shapeFactory;
  19. T = NullLocalizer.Instance;
  20. }
  21.  
  22. public void Describe(DescribeContext context)
  23. {
  24. Func<IShapeFactory, object> form =
  25. shape =>
  26. {
  27. var f = Shape.Form(
  28. Id: "ProductsListLayout",
  29. _HtmlProperties: Shape.Fieldset(
  30. Title: T("Html properties"),
  31. _ListId: Shape.TextBox(
  32. Id: "culture-id",
  33. Name: "CultureId",
  34. Title: T("culture id"),
  35. Description: T("The id to provide on the culture div element."),
  36. Classes: new[] { "textMedium", "tokenized" }
  37. ),
  38. _ListClass: Shape.TextBox(
  39. Id: "culture-classes",
  40. Name: "CultureClasses",
  41. Title: T("culture classes"),
  42. Description: T("The class to provide on the culture div element."),
  43. Classes: new[] { "textMedium", "tokenized" }
  44. ),
  45. _CultureTitle: Shape.TextBox(
  46. Id: "culturetitle-classes",
  47. Name: "CultureTitleClasses",
  48. Title: T("culture title classes"),
  49. Description: T("The class to provide on the culturetitle div element."),
  50. Classes: new[] { "textMedium", "tokenized" }
  51. ),
  52. _ProductsId:Shape.TextBox(
  53. Id: "products-id",
  54. Name: "ProductsId",
  55. Title: T("products id"),
  56. Description: T("The id to provide on the products div element."),
  57. Classes: new[] { "textMedium", "tokenized" }
  58. ),
  59. _ProductsClass:Shape.TextBox(
  60. Id: "products-classes",
  61. Name: "ProductsClasses",
  62. Title: T("products classes"),
  63. Description: T("The class to provide on the products div element."),
  64. Classes: new[] { "textMedium", "tokenized" }
  65. )
  66. )
  67. );
  68.  
  69. return f;
  70. };
  71. context.Form("ProductsListLayout", form);
  72. }
  73. }
  74. }

第三步需要新建一个ProductsListLayout的类,此类必须实现Orchard里ILayoutProvider接口,此类的作用有两点,第一:为Projections(后面章节有说明)选择布局供时提供布名称和说明,第二:调用构造具体布局的实现,并提供class 和 id传参,具体代码如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using Orchard.ContentManagement;
  6. using Orchard.DisplayManagement;
  7. using Orchard.Localization;
  8. using Orchard.Projections.Descriptors.Layout;
  9. using Orchard.Projections.Models;
  10. using Orchard.Projections.Services;
  11.  
  12. namespace UBOfficeTheme.Providers.Layouts
  13. {
  14. public class ProductsListLayout : ILayoutProvider
  15. {
  16. private readonly IContentManager _contentManager;
  17. protected dynamic Shape { get; set; }
  18. public Localizer T { get; set; }
  19.  
  20. public ProductsListLayout(IShapeFactory shapeFactory, IContentManager contentManager)
  21. {
  22. _contentManager = contentManager;
  23. Shape = shapeFactory;
  24. T = NullLocalizer.Instance;
  25. }
  26.  
  27. public void Describe(DescribeLayoutContext describe)
  28. {
  29. describe.For("Html", T("Html"), T("Html Layouts"))
  30. .Element("ProductsList", T("ProductsList"), T("Organizes content items in a ProductsList."),
  31. DisplayLayout,
  32. RenderLayout,
  33. "ProductsListLayout"
  34. );
  35. }
  36.  
  37. public dynamic RenderLayout(LayoutContext context, IEnumerable<LayoutComponentResult> layoutComponentResults)
  38. {
  39. string cultureId = context.State.CultureId;
  40. string cultureClasses = context.State.CultureClasses;
  41. string culturetitleClasses = context.State.CultureTitleClasses;
  42. string productsId = context.State.ProductsId;
  43. string productsClasses = context.State.ProductsClasses;
  44.  
  45. IEnumerable<dynamic> shapes =
  46. context.LayoutRecord.Display == (int)LayoutRecord.Displays.Content
  47. ? layoutComponentResults.Select(x => _contentManager.BuildDisplay(x.ContentItem, context.LayoutRecord.DisplayType))
  48. : layoutComponentResults.Select(x => x.Properties);
  49.  
  50. return Shape.ProductsList(
  51. Id: cultureId,
  52. Items: shapes,
  53. pcultureClasses: new[] { cultureClasses },
  54. pculturetitleClasses: new[] { culturetitleClasses },
  55. productsClasses: new[] { productsClasses },
  56. productsId : productsId
  57. );
  58. }
  59.  
  60. public Func<LayoutContext, LocalizedString> DisplayLayout { get; set; }
  61. }
  62. }

第四步新建一个LayoutShapes 此类必须实现Orchard里IDependency接口,此类的作用为本Theme解决方案里的所有自定义布局提供具体实现,定义布局方法是有三点需要注意,第一:在方法前必须要加上 [Shape]的属性,第二点:方法名称必须和ProductsListLayout类中的RenderLayout方法返回语句中Shape调用名称相同。第三点:定义的方法参数除去dynamic Display, TextWriter Output, HtmlHelper Html由Orchard本身框架提供,其余一部由ProductsListLayout类中的RenderLayout方法返回语句中的Shape调用方法传递,一部是自己定义给class使用的字典集合。具体代码如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Web;
  7. using System.Web.Mvc;
  8. using Orchard;
  9. using Orchard.Autoroute.Models;
  10. using Orchard.ContentManagement;
  11. using Orchard.DisplayManagement;
  12. using Orchard.Localization;
  13. using Orchard.UB.Portal.Models;
  14. using Orchard.UI.Resources;
  15.  
  16. namespace UBOfficeTheme.Providers.Layouts
  17. {
  18. public class LayoutShapes : IDependency
  19. {
  20. private readonly IWorkContextAccessor _workContextAccessor;
  21. private readonly IContentManager _contentManager;
  22. private readonly IOrchardServices _orchardServices;
  23.  
  24. public Localizer T { get; set; }
  25.  
  26. public LayoutShapes(IOrchardServices orchardServices,
  27. IWorkContextAccessor workContextAccessor, IContentManager contentManager)
  28. {
  29. _workContextAccessor = workContextAccessor;
  30. T = NullLocalizer.Instance;
  31. _contentManager = contentManager;
  32. _orchardServices = orchardServices;
  33. }
  34.  
  35. [Shape]
  36. public void ProductsList(dynamic Display, TextWriter Output, HtmlHelper Html, string Id,
  37. IEnumerable<dynamic> Items,
  38. IEnumerable<string> pcultureClasses,
  39. IDictionary<string, string> pcultureAttr,
  40. IEnumerable<string> pculturetitleClasses,
  41. IDictionary<string, string> pculturetitleAttr,
  42. IEnumerable<string> productsClasses,
  43. IDictionary<string, string> productsAttr,
  44. string productsId)
  45. {
  46. if (Items == null) return;
  47.  
  48. var items = Items.ToList();
  49. var itemsCount = items.Count;
  50. if (itemsCount < 1) return;
  51.  
  52. string baseUrl = _workContextAccessor.GetContext().CurrentSite.BaseUrl;
  53. var cultureDivTag = GetTagBuilder("div", Id, pcultureClasses, pcultureAttr);
  54. var cultureDivTitleTag = GetTagBuilder("div", string.Empty, pculturetitleClasses, pculturetitleAttr);
  55.  
  56. var proddetailDivTag = GetTagBuilder("div", productsId, productsClasses, productsAttr);
  57. var proddetailUlTag = GetTagBuilder("ul", productsId, productsClasses, productsAttr);
  58.  
  59. Output.Write(cultureDivTag.ToString(TagRenderMode.StartTag));
  60. Output.Write(cultureDivTitleTag.ToString(TagRenderMode.StartTag));
  61. Output.Write("<h6 class='fl'><strong></strong>新品推荐<span>NEW PRODUCTS</span></h6>");
  62. Output.Write(string.Format("<a href='{0}/{1}' class='fr'></a>", baseUrl, "executivedesk"));
  63. Output.Write(cultureDivTitleTag.ToString(TagRenderMode.EndTag));
  64. Output.Write("<div>");
  65. Output.Write(proddetailDivTag.ToString(TagRenderMode.StartTag));
  66. Output.Write("<a href=\"javascript:void(0)\" id=\"prev\" ></a>");
  67. Output.Write("<div>");
  68. Output.Write(proddetailUlTag.ToString(TagRenderMode.StartTag));
  69. for (int i = 0; i < items.Count; i++)
  70. {
  71. var pictureField = ((Orchard.ContentManagement.ContentItem)items[i].ContentItem).Parts.SelectMany(p => p.Fields).Where(f => f.Name.Contains("picture")).SingleOrDefault();
  72. var imglist = ((Orchard.MediaLibrary.Fields.MediaLibraryPickerField)pictureField).MediaParts.OrderBy(c => c.AlternateText).ToList();
  73. foreach (var item in imglist)
  74. {
  75. Output.Write("<li><a href='{2}/{3}'><img src='{0}' alt='优比家具-{1}'/></a></li>", item.MediaUrl, item.Title, baseUrl,item.Caption);
  76. }
  77. }
  78. Output.Write(proddetailUlTag.ToString(TagRenderMode.EndTag));
  79. Output.Write("</div>");
  80. Output.Write("<a href=\"javascript:void(0)\" id=\"next\" ></a>");
  81.  
  82. Output.Write(proddetailDivTag.ToString(TagRenderMode.EndTag));
  83. Output.Write(cultureDivTag.ToString(TagRenderMode.EndTag));
  84.  
  85. }
  86.  
  87. static TagBuilder GetTagBuilder(string tagName, string id, IEnumerable<string> classes, IDictionary<string, string> attributes)
  88. {
  89. var tagBuilder = new TagBuilder(tagName);
  90. tagBuilder.MergeAttributes(attributes, false);
  91. foreach (var cssClass in classes ?? Enumerable.Empty<string>())
  92. tagBuilder.AddCssClass(cssClass);
  93. if (!string.IsNullOrWhiteSpace(id))
  94. tagBuilder.GenerateId(id);
  95. return tagBuilder;
  96. }
  97. }
  98. }

到这里代码编写全部完成。下一篇介绍配置。

在Orchard CMS Theme 用代码定义布局Widgets的更多相关文章

  1. 在Orchard CMS Theme 用代码定义布局Widgets 配置

    在上篇中主要详细的叙述了代码的编写,这一篇主要讲解配置.可能有人会有疑问,在上一篇的代码里只有对数据的展示部分的编写,并没有提供数据源.这就是Orchard的强大之处,数据源是通过在后台配置的,那有人 ...

  2. [Orchard CMS系列] 创建主题(Writing a new theme)

    本文需要对Orchard CMS有基本了解. 开启模块 code generation 创建新的主题工程骨架 Codegen theme MyTheme 创建主题样式 src\Orchard.Web\ ...

  3. Orchard CMS中如何打包不带源码的模块

    在Orchard CMS的官网已经提供了文档说明如何打包,但是如果使用它的打包方式,打好的nuget包是带源代码的.如果是为开源系统写模块,不需要关注源代码是否可见.但是如果是用Orchard CMS ...

  4. SharePoint 2013 图文开发系列之代码定义列表

    在SharePoint的开发中,用Visual Studio自定义列表是经常会用到的,因为很多时候,我们并不会手动创建列表,而手动创建列表在测试服务器和正式机之间同步字段,也很麻烦,所以我们经常用代码 ...

  5. WPF中通过代码定义模板

    WPF中可以再XAML中定义模板,也可以通过C#代码定义模板,通过代码可能更清楚的看清其逻辑,而且代码的好处就是可以随时动态的去操作,而在XAML中定义的一般都是静态的. //控件呈现的显示内容1(这 ...

  6. SharePoint 2013 设置自己定义布局页

    在SharePoint中.我们常常须要自己定义登陆页面.错误页面.拒绝訪问等:不知道大家怎样操作,曾经自己常常在原来页面改或者跳转.事实上SharePoint为我们提供了PowerShell命令,来改 ...

  7. 在 Windows Azure 网站 (WAWS) 上对 Orchard CMS 使用 Azure 缓存

    编辑人员注释: 本文章由 Windows Azure 网站团队的项目经理 Sunitha Muthukrishna 撰写. 如果您当前的 OrchardCMS 网站在 Windows Azure 网站 ...

  8. Orchard CMS -Migration文件更新后数据库不更新的问题 new properties not updating after migrationData migration is not working?

    Orchard CMS - new properties not updating after migrationData migration is not working? If your mapp ...

  9. cucumber java从入门到精通(2)用代码定义步骤

    cucumber java从入门到精通(2)用代码定义步骤 上一节里我们定义了feature文件,feature文件就是自然语言描述的用例文件,它有一定的章法,具体的潜规则是: 使用Feature关键 ...

随机推荐

  1. python基础——2(基本数据类型及运算符)

    目录 为何数据要区分类型? 一.数字类型 1.整型int 2.浮点型float 二.字符串str 三.列表类型list 四.字典类型 五.布尔类型 运算符的介绍 一.算术运算符 二.比较运算符 三.赋 ...

  2. angular中的http拦截器Interceptors

    在angularJs中增加了一个对全局的http请求统一做出处理的api--interceptors Interceptors 有两个处理时机,分别是: 其它程序代码执行 HTTP 请求之后,在实际从 ...

  3. spring源码深度解析—Spring的整体架构和环境搭建

    概述 Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用.Spring是于2003 年兴起的一个轻量级的Java 开发框 ...

  4. 一个jboss启动shell脚本

    脚本1: #!/bin/sh # paulo@evencom.com.br #JBOSS_HOME JBOSS_HOME="/opt/app/jboss-eap-6.3" JAVA ...

  5. Leetcode 301.删除无效的括号

    删除无效的括号 删除最小数量的无效括号,使得输入的字符串有效,返回所有可能的结果. 说明: 输入可能包含了除 ( 和 ) 以外的字符. 示例 1: 输入: "()())()" 输出 ...

  6. 【ITOO 4】WCF中,分布式事务处理

    导读:事务可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源.通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠.在项目中,就有 ...

  7. 【组合数模板】HDU 6114 Chess

    http://acm.hdu.edu.cn/showproblem.php?pid=6114 [思路] 就是求C(m,n) [板] #include<iostream> #include& ...

  8. bzoj1709 [Usaco2007 Oct]Super Paintball超级弹珠 暴力

    [Usaco2007 Oct]Super Paintball超级弹珠 Description 奶牛们最近从著名的奶牛玩具制造商Tycow那里,买了一套仿真版彩弹游戏设备(类乎于真人版CS). Bess ...

  9. msp430入门编程47

    msp430中C语言的人机交互--菜单退出 msp430入门编程 msp430入门学习

  10. js面试题总结

    1.typeof和Object.prototype.toString typeof是js里面判断变量类型的一种方法,但这种方法没有Object.prototype.toString准确,前者有6种判断 ...