教程:在Orchard中创建自定义字段类型

  • 时间:
  • 浏览:3

  在《Orchard中的這個名词》一文中介绍过字段( Field)的概念,它是某种轻量级的内容部件,通常只能另两个 字段,不能 是另两个 文本输入框,或是另两个 日期选择框。亲戚亲戚亲们不能 把它理解为某种输入控件,原因 称为字段类型。

  再来回顾一下《Orchard中的内容管理》中的介绍的這個概念,在Orchard中的任何数据都不能 把它理解为内容(Content)。页面是内容、博客是内容、文章也是内容。整个网站假如由這個不這個型的内容项(Content Item)构成的。对這個不同内容的类型定义假如内容类型(Content Type)。而内容类型则是通过若干个不同的内容部件(Content Part)组成。实在对于定义這個简单的内容类型,原因 说后续无繁复处置要求的内容类型时,亲戚亲戚亲们假如一定非得去创建内容部件,而完整篇 不能 用這個现有的内容部件在再加若干字段(Field)就不能 了。

  字段(Field)和部件(Part)的区别在于,字段是不不单独去创建表来存储数据的,假如通过Orchard框架的功能将其以xml的形式存储到Orchard_Framework_ContentItemRecord表的Data字段中,而Part则时需创建相应的表去存储這個记录。這個存储上的差异就决定了,字段形式适用于简单场景,如假如单纯显示另两个 单一实体;而部件法律依据适用于后续有较繁复的逻辑处置的场景,如处在一对多、多的多关系等。更进一步的来说,另两个 部件不能 理解为另两个 完整篇 功能的业务实体,而另两个 字段假如业务实体上的另两个 属性。下面亲戚亲戚亲们就通过另两个 示例来介绍在Orchard中怎么才能 才能 定义字段类型。

目标

  我时需定义另两个 活动类型(Event),包括标题,时间,地点等。原因 用Part的做法,亲戚亲戚亲们当但会 能 把时间和地点再加一起去做成活动部件。原因 要用字段的形式来做,亲戚亲戚亲们就不能 再加另两个 Route部件,再加另两个 文本字段(TextField)即可。文本字段是Orchard自带的字段类型,功能假如另两个 简单文本输入框。实在字段类型还不能 做的更加友好些,比如:输入时间的很久不能 弹出另两个 日期选择控件,输入地点的很久不能 选择所在城市。关于日期时间的字段类型Orchard应用商店原因 有了,亲戚亲戚亲们不能 去安装另两个 ,在Gallery中搜索DateTimeField即可。现在亲戚亲戚亲们时需创建另两个 地点字段类型(LocaleField),包括另两个 城市选择和另两个 地点输入。

创建模块

  创建另两个 新的字段类型实在和创建另两个 模块一样,亲戚亲戚亲们就是能 用命令行工具首先创建另两个 代码模板。输入:codegen module MyCompany.LocaleField,运行成功后在Orchard处置方案的Modules目录下就会多出另两个 MyCompany.LocaleField的项目了。

建立字段模型

  亲戚亲戚亲们不能 在此项目中再加另两个 Fields文件夹,并在该目录中再加另两个 LocaleField.cs文件,代码如下:

LocaleField.cs 

using System;

using Orchard.ContentManagement;

using Orchard.ContentManagement.FieldStorage;

namespace MyCompany.LocaleField.Fields



{

/// <summary>

/// 自定义的字段时需继承ContentField类

/// Storage共就是在ContentField中获取或设置值

/// </summary>

public class LocaleField : ContentField

{

public string Locale

{

get

{

var value = Storage.Get<string>();

return value;

}

set

{

Storage.Set(value == null ? String.Empty : value);

}

}

  另两个 字段类型时需被定为另两个 类,但会 时需继承于ContentField,这么 亲戚亲戚亲们就不能 利用字段类型的這個现有功能,比如数据存储。字段类型的数据后会以字符串的形式存储到数据库中的,亲戚亲戚亲们通过定义這個类就不能 将字段数据转再加亲戚亲戚亲们我应该 的类型比如,日期类型,数字类型等。字段数据亲戚亲戚亲们不不创建相应的表去存储,Orchard框架会替亲戚亲戚亲们完成这项工作。這個字段数据,将以xml的形式存储到Orchard_Framework_ContentItemRecord表的Data字段中,如:

建立视图模型

  原因 另两个 地点字段是由城市和地址组成,就是 本例亲戚亲戚亲们还时需建立另两个 视图模型来作为视图的Model,而后会直接用LocaleField作为视图的Model。实在这步工作不一定是时需的,但会 建立另两个 视图模型却是另两个 好的习惯,这么 不能 使亲戚亲戚亲们的代码看起来更清晰更易懂。在此项目中再加另两个 ViewModels目录,并在该目录下再加另两个 LocaleFieldViewModel.cs文件,输入以下代码:

LocaleFieldViewModel.cs 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

namespace MyCompany.LocaleField.ViewModels



{

public class LocaleFieldViewModel

{

public string Name { get; set; }

public string City { get; set; }

public string Address { get; set; }

/// <summary>



/// 作为示例这里就只简单构造這個城市的数据

/// 原因 要做成产品,当然这每种时需处置的更好些

/// </summary>

public SelectList CityList

{

get

{

var lst = new List<SelectListItem>();

lst.Add(new SelectListItem { Text = "北京", Value = "北京" });

lst.Add(new SelectListItem { Text = "上海", Value = "上海" });

lst.Add(new SelectListItem { Text = "天津", Value = "天津" });

lst.Add(new SelectListItem { Text = "重庆", Value = "重庆" });

lst.Add(new SelectListItem { Text = "武汉", Value = "武汉" });

return new SelectList(lst, "Value", "Text", this.City);

}

}

}

写驱动器

  正如前文所说,字段类型实在是某种轻量级的部件。和部件一样它也时需另两个 驱动器(Driver)来处置它的呈现逻辑,假如它不时需处置器(Handler)来处置它的数据存储。原因 Orchard框架原因 帮亲戚亲戚亲们实现了這個点。亲戚亲戚亲们在此项目中再加另两个 Drivers目录,并在该目录下创建另两个 LocaleFieldDriver.cs文件,输入以下代码:

LocaleFieldDriver.cs 

using System;

using JetBrains.Annotations;

using Orchard;

using Orchard.ContentManagement;

using Orchard.ContentManagement.Drivers;

using MyCompany.LocaleField.ViewModels;

using Orchard.Localization;

namespace MyCompany.LocaleField.Drivers



{

public class LocaleFieldDriver : ContentFieldDriver<Fields.LocaleField>

{

/// <summary>

/// 定义模板查找规则,在Views目录下按照Fields/MyCompany.Locale规则查找模板

/// 比如显示画面就直接查找Fields目录下MyCompany.Locale.cshtml文件。(注:aspx模板也是支持的)

/// 编辑画面会查找EditorTemplates目录下的Fields\MyCompany.Locale.cshtml文件

/// </summary>

private const string TemplateName = "Fields/MyCompany.Locale"; // EditorTemplates/Fields/MyCompany.Locale.cshtml

/// <summary>



/// 获取字段前缀

/// 不能 使编辑画面中各字段的表单控件后会唯一的名称,不至于出显同名冲突。

/// </summary>

/// <param name="field"></param>

/// <param name="part"></param>

/// <returns></returns>

private static string GetPrefix(ContentField field, ContentPart part)

{

return part.PartDefinition.Name + "." + field.Name;

}

/// <summary>



/// 显示画面

/// </summary>

/// <param name="part"></param>

/// <param name="field"></param>

/// <param name="displayType"></param>

/// <param name="shapeHelper"></param>

/// <returns></returns>

protected override DriverResult Display(ContentPart part, Fields.LocaleField field, string displayType, dynamic shapeHelper)

{

var value = field.Locale;

var viewModel = new LocaleFieldViewModel



{

Name = field.Name,

//地点数据由城市和地址构成,城市和地址用逗号分隔,如:上海,浦东新区张杨路XXX号

City = string.IsNullOrEmpty(value) ? "" : value.Substring(0, value.IndexOf(',')),

Address = string.IsNullOrEmpty(value) ? "" : value.Substring(value.IndexOf(',') + 1)

};

return ContentShape("Fields_MyCompany_Locale", // this is just a key in the Shape Table



() =>

shapeHelper.Fields_MyCompany_Locale( // Fields_MyCompany_Locale是另两个 动态类型,是视图Fields/MyCompany.Locale.cshtml的module,其中的Model属性,是LocaleFieldViewModel

Model: viewModel)

);

}

/// <summary>



/// 编辑画面显示

/// </summary>

/// <param name="part"></param>

/// <param name="field"></param>

/// <param name="shapeHelper"></param>

/// <returns></returns>

protected override DriverResult Editor(ContentPart part, Fields.LocaleField field, dynamic shapeHelper)

{

var value = field.Locale;

var viewModel = new LocaleFieldViewModel



{

Name = field.Name,

City = string.IsNullOrEmpty(value) ? "" : value.Substring(0, value.IndexOf(',')),

Address = string.IsNullOrEmpty(value) ? "" : value.Substring(value.IndexOf(',') + 1)

};

return ContentShape("Fields_MyCompany_Locale_Edit", // this is just a key in the Shape Table



() => shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: viewModel, Prefix: GetPrefix(field, part)));

}

/// <summary>



/// 编辑画面Post

/// </summary>

/// <param name="part"></param>

/// <param name="field"></param>

/// <param name="updater"></param>

/// <param name="shapeHelper"></param>

/// <returns></returns>

protected override DriverResult Editor(ContentPart part, Fields.LocaleField field, IUpdateModel updater, dynamic shapeHelper)

{

var viewModel = new LocaleFieldViewModel();

if(updater.TryUpdateModel(viewModel, GetPrefix(field, part), null, null))



{

field.Locale = viewModel.City + "," + viewModel.Address;

}

return Editor(part, field, shapeHelper);



}

  首先,和部件驱动器不一样是:字段驱动器时需继承于ContentFieldDriver,并指定泛型参数T为LocaleField类型。其次,还时需定义另两个 GetPrefix的静态法律依据,这么 就不能 使编辑画面中各字段的表单控件后会唯一的名称,不至于出显同名冲突。最后,亲戚亲戚亲们时需定义十好多个 法律依据,這個于Controller中的action,用于构建這個字段类型的显示画面,编辑画面,以及编辑画面Post处置。

写模板

  有了驱动器和视图模型,就共要有了MVC中的 Controller 和Model,现在我时需创建的是這個字段类型的View,也假如Orchard概念中的模板(Templates)。根据在驱动器中所定义的模板查找规则,亲戚亲戚亲们时需在Views目录下创建另两个 Fields目录,并在该目录下创建另两个 MyCompany.Locale.cshtml文件作为该自定义字段的显示画面,代码如下:

Fields\MyCompany.Locale.cshtml 

<!--這個画面的Model是另两个 动态类型,這個动态类型是在相应的驱动器中定义的-->

<!--這個动态类型的其中另两个 属性Model是另两个 LocaleFieldViewModel类型的-->

<p class="text-field">

<span class="name">@Model.Model.Name:</span>

@Model.Model.City

@Model.Model.Address

</p> 

  接着,亲戚亲戚亲们还时需在Views下面创建另两个 EditorTemplates目录,并在其下面创建另两个 Fields目录,但会 再在后面 在创建另两个 MyCompany.Locale.cshtml文件作为该自定义字段的编辑画面,代码如下:

EditorTemplates\Fields\MyCompany.Locale.cshtml 

@model MyCompany.LocaleField.ViewModels.LocaleFieldViewModel

<fieldset>

<label for="@Html.FieldIdFor(m => Model.City)">@Model.Name</label>

City:

@Html.DropDownListFor(m => m.City, this.Model.CityList)

Address:

@Html.TextBoxFor(m => m.Address)

</fieldset> 

  最后亲戚亲戚亲们别忘了再加另两个 Placement.info文件,这么這個文件亲戚亲戚亲们很久定义的模版就无法在页面中显示,关于Placement.info文件的介绍不能 查看《Understanding the placement.info File》,这里亲戚亲戚亲们输入以下代码:

Placement.info 

<Placement>

<Place Fields_MyCompany_Locale_Edit="Content:2.5"/>

<Match DisplayType="SummaryAdmin">



<Place Fields_MyCompany_Locale="Content"/>

</Match>

<Place Fields_MyCompany_Locale="Content:after"/>



</Placement>

使用自定义字段

  经过以上這個简单的工作后,另两个 新的字段类型就定义成功。下面亲戚亲戚亲们定义另两个 新的活动类型,来使用亲戚亲戚亲们刚创建好的地点字段类型。

  首先,用管理员帐号登录并进入管理后台(Dashboard)点击Content菜单,选择Content Types选项卡,点击Create new type按钮。在出显的画面中输入以下内容:

  但会 ,点击Create按钮,选择活动类型时需含晒 的Part,在这里亲戚亲戚亲们就选择十好多个 基本的部件:Route路由部件,用于显示活动标题和为此活动指定另两个 路由(Url);Common通用部件,用于显示活动发起人和发起时间;Containable集合部件,能让活动以列表形式在页面上呈现。

  接下来,亲戚亲戚亲们就在這個活动类型中再加另两个 字段:另两个 表示活动时间(When)用Orchard应用商店中提供的DateTimeField字段类型;另两个 表示活动地点(Where)用亲戚亲戚亲们刚创建的LocaleField字段类型。

  最后亲戚亲戚亲们就不能 在Content Types列表中找到刚创建的Event类型,点击Create New Evnet来创建新的活动了。

编辑画面

管理活动列表画面

活动详情画面

功能扩展

  以上介绍的地点字段类型实在是另两个 非常简单的示例。但会 自定义字段类型,却还是有更多可扩展的空间。比如,亲戚亲戚亲们还不能 在地点字段中增加另两个 国家的概念、省市的概念并实现其联动选择。但会 国家、省市的数据还不能 以xml的形式存储在文件中,这么 比写在代码里要方便维护。亲戚亲戚亲们就是能 为這個自定义字段增加若干设置,如:是是是否是是显示国家选择,或默认显示那个国家,或是是是否是是允许获取当前用户的位置作为默认值,等等。关于怎么才能 才能 再加自定义字段设置功能的介绍可参考《Creating a Custom Field Type》中的内容。

总结

  通过本文,亲戚亲戚亲们讲解了Orchard中字段(Field)的概念,并介绍了怎么才能 才能 自定义另两个 新的字段类型,也介绍了字段的用法,一起去还指明了字段和部件的区别。实在自定义字段看似简单实在功能却十分实用,通过组合自定义字段,亲戚亲戚亲们不能 方便的组织一张自定义表单。自定义字段的类型也是富足多样的,本文就介绍了某种:纯文本字段、日期时间字段,地点字段,更多样的字段类型就要看亲戚亲戚亲们的想象力了,套用得话:这么做只能,只能想只能。

参考文档http://www.orchardproject.net/docs/Creating-a-custom-field-type.ashx

示例代码

点击下载(在Orchard后台Modules菜单的Installed选项卡中安装压缩包里的nupkg文件)

Orchard下载

本文转自:二十四画生的博客