内容部件(Content part)是一个可重复利用的功能或UI(或两者兼备). 它可以附加到Orchard的任何content type中. 例如一些内容部件中包含了Route part(使其允许通过前端url来访问), Tags part(使其可以包含关键字和标记), Menu part(使其可以添加到主菜单中).
本教程从头开始教你如何创建一个内容部件, 利用Orchard中的scaffolding feature来作为一个有效的工具. 在本教程中我们假设你使用visual studio来开发内容部件, 但这并不是必须的, 你可以选择你想用的开发工具.
在本教程中, 我们将会创建一个自定义的地图部件,它可以通过设置经纬度值将该坐标点显示在地图上并将该地图显示在content item中.
重要提示: 在你生成模块前, 你必须为Orchard下载安装并启用Code Generation模块(译者注: 在Orchard的Modules设置中启用Code Generation模块). 想要了解更多信息请查看 Command line Code Generation.
我们创建一个名为"Maps"的模块, 稍后将用这个模块来实现Map part的所有功能. 在Orchard解决方案中添加一个新的项目. 假设你已经有了Orchard的源代码, 启动 visual studio 2010 并打开"src"目录下的Orchard.sln文件.
在Orchard的命令提示符中输入"codegen module Maps / IncludeInSolution:true". 参数 "IncludeInSolution"会告诉Orchard在Orchard.sln中创建一个名为"Maps"的模块解决方案.
orchard> codegen module Maps /IncludeInSolution:true
Creating module Maps
Module Maps created successfully
在执行该命令之后, VS会弹出一个提示重新加载解决方案的对话框. 请点击"Reload"
Maps模块项目已经添加到了解决方案, 并且带有一些默认的文件和目录
打开Maps项目根目录下的Module.txt. 这个文件定义一些与你模块相关的信息, 例如模块的名称. 描述, 版本, 作者以及模块的分类. Module.txt同样可以放置一些额外的信息, 例如模块的依赖项, 在这里我们不会添加依赖项. 因为我们的模块非常简单, 仅仅是一个单独的"Maps"没有任何的依赖项. 编辑Module.txt如下所示:
Name: Maps
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
Version: 1.0.0
OrchardVersion: 1.0.0
Description: Adds a map image to content items, based on longitude and latitude.
Features:
Maps:
Description: Adds a map image to content items, based on longitude and latitude.
Category: Geolocation
我们现在开始编写Maps部件. 首先, 我们需要一个用于存放Maps部件数据的类. 按照惯例数据类应该存放在项目的Models目录下. 右键点击"Modules"文件夹, 选择"添加>类"添加一个名为"Map.cs"的文件.
在Orchard中, 内容部件的数据是由一个Record类来表示的, 其表示存储到数据库中表的字段, 而且ContentPart类使用它来进行存储. 添加MapRecord(ContentPartRecord) 和 MapPart(ContentPaert)类:
using System.ComponentModel.DataAnnotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Records;
namespace Maps.Models {
public class MapRecord : ContentPartRecord {
public virtual double Latitude { get; set; }
public virtual double Longitude { get; set; }
}
public class MapPart : ContentPart<MapRecord> {
[Required]
public double Latitude
{
get { return Record.Latitude; }
set { Record.Latitude = value; }
}
[Required]
public double Longitude
{
get { return Record.Longitude; }
set { Record.Longitude = value; }
}
}
}
现在生成Maps项目并确保Record类编译成功
下一步, 为我们的Maps模块创建一个Data migration. 为什么我们需要一个migration类呢? 这是因为创建一个Record类和Part类并未真正意义上的影响到数据库. 而一个data migration的作用就在于当启用该模块时, 它就会告诉Orchard如何去更新数据库的架构(migration在模块被激活时执行). migration同样可以更新一个旧版本的数据库架构 - 这是一个高级主题并包含在本教程中.
可以通过Orchard的命令提示符去创建一个migration class. 执行命令"codegen datamigration Maps"
orchard> codegen datamigration Maps
Creating Data Migration for Maps
Data migration created successfully in Module Maps
VS又会提示重新加载解决方案, 重新加载后migration classes将会出现在项目中
在codegen命令生成的migration类中包含一个Create()方法, 该方法基于项目中的Record类来创建数据库表结构. 因为我们只有一个MapRecord类, 而且该类中只包含Latitude和Longitude这两个属性, 所以migration类看起来非常简单. 注意, Create方法在你模块被激活时调用, 并对数据库做出相应的更新.
using System;
using System.Collections.Generic;
using System.Data;
using Maps.Models;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Builders;
using Orchard.Core.Contents.Extensions;
using Orchard.Data.Migration;
namespace Maps.DataMigrations {
public class Migrations : DataMigrationImpl {
public int Create() {
// Creating table MapRecord
SchemaBuilder.CreateTable("MapRecord", table => table
.ContentPartRecord()
.Column("Latitude", DbType.Double)
.Column("Longitude", DbType.Double)
);
ContentDefinitionManager.AlterPartDefinition(typeof(MapPart).Name, cfg => cfg.Attachable());
return 1;
}
}
}
在migration中还添加AlterPartDefinition, 这是为了该部件可以附加任何content type (需using Maps.Modules命名空间).
现在让我们添加一个handler. handler在Orchard中用于定义一个部件的"行为", 处理事件或在部件呈现之前操作数据. 因为我们的Map部件是非常的简单, 所以在其构造函数中仅指定MapRecord类型的IRepository参数用于数据的存储. 在Maps项目的Handler文件夹下添加MapHandler.cs并加入以下内容:
using Maps.Models;
using Orchard.ContentManagement.Handlers;
using Orchard.Data;
namespace Maps.Handlers {
public class MapHandler : ContentHandler {
public MapHandler(IRepository<MapRecord> repository) {
Filters.Add(StorageFilter.For(repository));
}
}
}
我们将添加一个driver. 在Orchard中driver是一个类, 它在不同的上下文中关联Map部件需要呈现的样子(译者注:可以把它理解为MVC中的Controller). 例如, Map部件在前端呈现时, "Display"方法根据不同的显示类型(例如, "details" 或 "summary")来决定需要呈现的模板名称. 同样的, driver中的"Editor"方法定义编辑时呈现的模板(键入精度和纬度值的字段). (译者注:dirver中有两个Editor方法, 一个用于GET请求,即编辑界面显示方法, 另一个重载用于POST请求, 即编辑界面提交方法). Drivers\MapDriver.cs的代码如下:
using Maps.Models;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
namespace Maps.Drivers {
public class MapDriver : ContentPartDriver<MapPart> {
protected override DriverResult Display(
MapPart part, string displayType, dynamic shapeHelper) {
return ContentShape("Parts_Map", () => shapeHelper.Parts_Map(
Longitude: part.Longitude,
Latitude: part.Latitude));
}
//GET
protected override DriverResult Editor(
MapPart part, dynamic shapeHelper) {
return ContentShape("Parts_Map_Edit",
() => shapeHelper.EditorTemplate(
TemplateName: "Parts/Map",
Model: part,
Prefix: Prefix));
}
//POST
protected override DriverResult Editor(
MapPart part, IUpdateModel updater, dynamic shapeHelper) {
updater.TryUpdateModel(part, Prefix, null, null);
return Editor(part, shapeHelper);
}
}
}
现在我们可以在Visual Studio中添加显示和编辑的视图了.首先在Maps项目的Views目录下添加Parts和EditorTemplates/Parts目录, 然后在Part目录和EditorTemplates目录下都添加一个Map.cshtml文件.
Views/EditorTemplate/Parts/Map.cshtml的内容如下:
@model Maps.Models.MapPart
<fieldset>
<legend>Map Fields</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Latitude)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.Latitude)
@Html.ValidationMessageFor(model => model.Latitude)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Longitude)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.Longitude)
@Html.ValidationMessageFor(model => model.Longitude)
</div>
</fieldset>
Views/Parts/Map.cshtml的内容如下:
<img alt="Location" border="1" src="http://maps.google.com/maps/api/staticmap?
&zoom=14
&size=256x256
&maptype=roadmap
&markers=color:blue|@Model.Latitude,@Model.Longitude
&sensor=false" />
以上的两个模板都会在一个更大的页面合成后呈现. 因为系统需要知道这些模板在合成面中呈现的位置和顺序, 所以我们需要在项目的根目录添加一个名为"placement.info"的文件. 文件内容如下:
<Placement>
<Place Parts_Map="Content:10"/>
<Place Parts_Map_Edit="Content:7.5"/>
</Placement>
这些内容描述 Map 部件显示模式在"Content"区域的第十个位置上呈现, 编辑模式在"Primary"区域的第二个位置上呈现.(译者注: 不明白).
要激活Map部件, 请到Modules -> Features中启用它.
你可以试着将Map部件附加到系统的任何Content Type中, 使用Orchard管理员面板中的"Content Type"功能. 让我们把他添加到一个已存在的content type(译者注:这家伙的废话可真多….). 即, 我们在Creating costom content types文章中所创建的自定义"Event"内容类型(content type). 如果你还没有看过那个文章或你并没有"Event"类型, 那么你可以把它添加到Page Content中(步骤和这个相同).
在"Manage Content Types"页面, 点击"Edit"来编辑类型
Map部件会显示在可用部件列表中, 选中并点击"Save".
现在到"Manage Content" 编辑事件内容项. (译者注: 你可以看到Map部件已经躺在那了)
在你站点的前端页面你可以看到Map部件所产生的效果了
转载请注明出处: dotnet-lc's blog. 本文地址: http://www.dotnet-lc.com/write-a-content-part
原文链接: http://docs.orchardproject.net/Documentation/Writing-a-content-part
Orchard的简单介绍: http://orchardproject.net/mission
Orchard中文站点: http://www.orchardch.com/
PS: Orchard在国内并不怎么流行, 国内对它的介绍及教材也不是太多. 好像并没有太多的人去研究它, 但在我看来它是很有价值的... /坏笑