字段(Field)和部件(Part)的区别在于,字段是不用单独去创建表来存储数据的,而是通过Orchard框架的功能将其以xml的形式存储到Orchard_Framework_ContentItemRecord表的Data字段中,而Part则需要创建相应的表去存储这些记录。这种存储上的差异就决定了,字段形式适用于简单场景,如只是单纯显示一个单一实体;而部件方式适用于后续有较复杂的逻辑处理的场景,如存在一对多、多的多关系等。更进一步的来说,一个部件可以理解为一个完整功能的业务实体,而一个字段只是业务实体上的一个属性。下面我们就通过一个示例来介绍在Orchard中如何定义字段类型。
目标
创建模块
建立字段模型
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);
}
}
}
建立视图模型
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);
}
}
}
写驱动器
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);
}
}
写模板
<!--这个动态类型的其中一个属性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文件作为该自定义字段的编辑画面,代码如下:
<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》,这里我们输入以下代码:
<Place Fields_MyCompany_Locale_Edit="Content:2.5"/>
<Match DisplayType="SummaryAdmin">
<Place Fields_MyCompany_Locale="Content"/>
</Match>
<Place Fields_MyCompany_Locale="Content:after"/>
</Placement
使用自定义字段
编辑画面
管理活动列表画面
活动详情画面
功能扩展
总结
参考文档
示例代码
点击下载 (在Orchard后台Modules菜单的Installed选项卡中安装压缩包里的nupkg文件 )
==========================================
作者:二十四画生
转载请注明来源于博客园——二十四画生的Blog,并保留有原文链接。