Orchard:生成一个自定义字段类型

    在Orchard中定义新的content types时可以使用字段,现在Orchard只内置了一个文本类型字段,在实际应用中,我们肯定会遇到添加自己的字段类型,然后在新的content types上使用。这篇文章将教给大家的是在http://orcharddatetimefield.codeplex.com中的自定义日期时间数据类型。如果对如何生成一个模块不清楚,可以先看看本系列的前几篇文章。

目标

这个练习做完之后,我们将新增一个新的字段类型,使用界面如下图所示:有一个日期和时间编辑器

201102171223134116.png

生成一个模块

 
  
codegen module CustomFields / IncludeInSolution: true

现在在Modules目录下有一个新的目录: CustomFields,更改 module.txt:
ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
Name: CustomFields
AntiForgery: enabled
Author: Me
Website: http:
// orcharddatetimefield.codeplex.com
Version: 0.6 . 1
OrchardVersion:
0.8 . 0
Description: A bunch of custom fields
for use in your custom content types.
Features:
CustomFields:
Description: Custom fields
for Orchard.
Category: Fields
DateTimeField:
Description: A date and time field with a friendly UI.
Category: Fields
Dependencies: CustomFields, Orchard.jQuery, Common, Settings

这里我们定义了两个features,因为这个模块最后包括多个字段,我们想要区分这个模块的默认功能和日期字段功能,这个也正好可以演示一下分类和依赖的使用。

生成字段

CustomFields目录下生成目录Fields,添加文件DateTimeField.cs:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
using System;
using System.Globalization;
using Orchard.ContentManagement;
using Orchard.ContentManagement.FieldStorage;
using Orchard.Environment.Extensions;

namespace CustomFields.DateTimeField.Fields
{
[OrchardFeature(
" DateTimeField " )]
public class DateTimeField : ContentField
{

public DateTime ? DateTime
{
get
{
var value
= Storage.Get < string > ();
DateTime parsedDateTime;

if (System.DateTime.TryParse(value, CultureInfo.InvariantCulture,
DateTimeStyles.AdjustToUniversal,
out parsedDateTime))
{

return parsedDateTime;
}

return null ;
}

set
{
Storage.Set(value
== null ?
String.Empty :
value.Value.ToString(CultureInfo.InvariantCulture));
}
}
}
}

这个自定义字段DateTimeField是从 ContentField继承下来的,ContentField提供一些字段值存储等服务。这个字段将存储为strings。

生成一个view model

生成一个或多个view models虽然不是强制的,但是一个好的实践。View model将被用来封装model用于展现而用的模型。在一个新的ViewModels目录下添加文件DateTimeFieldViewModel.cs:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
namespace CustomFields.DateTimeField.ViewModels
{

public class DateTimeFieldViewModel
{

public string Name { get ; set ; }

public string Date { get ; set ; }
public string Time { get ; set ; }

public bool ShowDate { get ; set ; }
public bool ShowTime { get ; set ; }
}
}

生成字段设置

Create a Settings folder and add the following DateTimeFieldSettings.cs file to it:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
namespace CustomFields.DateTimeField.Settings
{

public enum DateTimeFieldDisplays
{
DateAndTime,
DateOnly,
TimeOnly
}

public class DateTimeFieldSettings
{
public DateTimeFieldDisplays Display { get ; set ; }
}
}
这里我们定义了一个设类,这个类是个很简单的类,Display是一个枚举值

写一个driver

Drivers目录下添加文件DateTimeFieldDriver.cs

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
using System;
using CustomFields.DateTimeField.ViewModels;
using JetBrains.Annotations;
using Orchard;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using CustomFields.DateTimeField.Settings;
using Orchard.Localization;

namespace CustomFields.DateTimeField.Drivers
{
[UsedImplicitly]
public class DateTimeFieldDriver : ContentFieldDriver < Fields.DateTimeField >
{
public IOrchardServices Services { get ; set ; }

// EditorTemplates/Fields/Custom.DateTime.cshtml
private const string TemplateName = " Fields/Custom.DateTime " ;

public DateTimeFieldDriver(IOrchardServices services)
{
Services
= services;
T
= NullLocalizer.Instance;
}

public Localizer T { get ; set ; }

private static string GetPrefix(ContentField field, ContentPart part)
{
// handles spaces in field names
return (part.PartDefinition.Name + " . " + field.Name)
.Replace(
" " , " _ " );
}

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

var settings
= field.PartFieldDefinition.Settings
.GetModel
< DateTimeFieldSettings > ();
var value
= field.DateTime;

return ContentShape( " Fields_Custom_DateTime " , // key in Shape Table
// this is the actual Shape which will be resolved
// (Fields/Custom.DateTime.cshtml)
s =>
s.Name(field.Name)
.Date(value.HasValue
?
value.Value.ToLocalTime().ToShortDateString() :
String.Empty)
.Time(value.HasValue
?
value.Value.ToLocalTime().ToShortTimeString() :
String.Empty)
.ShowDate(
settings.Display
== DateTimeFieldDisplays.DateAndTime ||
settings.Display
== DateTimeFieldDisplays.DateOnly)
.ShowTime(
settings.Display
== DateTimeFieldDisplays.DateAndTime ||
settings.Display
== DateTimeFieldDisplays.TimeOnly)
);
}

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

var settings
= field.PartFieldDefinition.Settings
.GetModel
< DateTimeFieldSettings > ();
var value
= field.DateTime;

if (value.HasValue)
{
value
= value.Value.ToLocalTime();
}

var viewModel
= new DateTimeFieldViewModel
{
Name
= field.Name,
Date
= value.HasValue ?
value.Value.ToLocalTime().ToShortDateString() :
"" ,
Time
= value.HasValue ?
value.Value.ToLocalTime().ToShortTimeString() :
"" ,
ShowDate
=
settings.Display
== DateTimeFieldDisplays.DateAndTime ||
settings.Display
== DateTimeFieldDisplays.DateOnly,
ShowTime
=
settings.Display
== DateTimeFieldDisplays.DateAndTime ||
settings.Display
== DateTimeFieldDisplays.TimeOnly

};

return ContentShape( " Fields_Custom_DateTime_Edit " ,
()
=> shapeHelper.EditorTemplate(
TemplateName: TemplateName,
Model: viewModel,
Prefix: GetPrefix(field, part)));
}

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

var viewModel
= new DateTimeFieldViewModel();

if (updater.TryUpdateModel(viewModel,
GetPrefix(field, part),
null , null ))
{
DateTime value;

var settings
= field.PartFieldDefinition.Settings
.GetModel
< DateTimeFieldSettings > ();
if (settings.Display == DateTimeFieldDisplays.DateOnly)
{
viewModel.Time
= DateTime.Now.ToShortTimeString();
}

if (settings.Display == DateTimeFieldDisplays.TimeOnly)
{
viewModel.Date
= DateTime.Now.ToShortDateString();
}

if (DateTime.TryParse(
viewModel.Date
+ " " + viewModel.Time, out value))
{
field.DateTime
= value.ToUniversalTime();
}
else
{
updater.AddModelError(GetPrefix(field, part),
T(
" {0} is an invalid date and time " ,
field.Name));
field.DateTime
= null ;
}
}

return Editor(part, field, shapeHelper);
}
}
}
DateTimeFieldDriver 从 ContentFieldDriver 继承下来。

一开始通过依赖注入获取localizer 依赖对象,以便我们能够通过代码获取本地化字符。静态的方法GetPrefix是一个用来定义字段类型示例在数据库中唯一列名的前缀。

Display和Editor获取字段的设置和值来构建shapes。

写模板

Views目录下生成一个FieldsEditorTemplates目录,然后在EditorTemplates下生成一个Fields目录。

Views/Fields下新增文件Custom.DateTime.cshtml:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
< p class = " text-field " >< span class = " name " > @Model.Name: </ span >
@if(Model.ShowDate) {
< text > @Model.Date </ text > }
@if(Model.ShowTime) {
< text > @Model.Time </ text > }
</ p >
Views/EditorTemplates/Fields 下生成文件Custom.DateTime.cshtml:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
@model CustomFields.DateTimeField.ViewModels.DateTimeFieldViewModel

@{
Style.Include(
" datetime.css " );
Style.Require(
" jQueryUI_DatePicker " );
Style.Require(
" jQueryUtils_TimePicker " );
Style.Require(
" jQueryUI_Orchard " );

Script.Require(
" jQuery " );
Script.Require(
" jQueryUtils " );
Script.Require(
" jQueryUI_Core " );
Script.Require(
" jQueryUI_Widget " );
Script.Require(
" jQueryUI_DatePicker " );
Script.Require(
" jQueryUtils_TimePicker " );
}

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

@if ( Model.ShowDate ) {
< label class = " forpicker "
for = " @Html.FieldIdFor(m => Model.Date) " > @T( " Date " ) </ label >
< span class = " date " > @Html.EditorFor(m => m.Date) </ span >
}

@if ( Model.ShowTime ) {
< label class = " forpicker "
for = " @Html.FieldIdFor(m => Model.Time) " > @T( " Time " ) </ label >
< span class = " time " > @Html.EditorFor(m => m.Time) </ span >
}
@if(Model.ShowDate) {
< text > @Html.ValidationMessageFor(m => m.Date) </ text > }
@if(Model.ShowTime) {
< text > @Html.ValidationMessageFor(m => m.Time) </ text > }
</ fieldset >

@using(Script.Foot()) {
< script type = " text/javascript " >
$(function () {
$(
" #@Html.FieldIdFor(m => Model.Date) " ).datepicker();
$(
" #@Html.FieldIdFor(m => Model.Time) " ).timepickr();
});
</ script >
}
为了指定显示顺序和位置,在项目根目录下增加文件Placement.info:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
< Placement >
< Place Fields_Custom_DateTime_Edit = " Content:2.5 " />
< Place Fields_Custom_DateTime = " Content:2.5 " />
</ Placement >
管理字段设置

到现在还没有完全做完,我们还需要关心如何管理和持久化字段的设置,在Settings目录下增加文件DateTimeFieldEditorEvents.cs:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
using System.Collections.Generic;
using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Builders;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentManagement.ViewModels;

namespace CustomFields.DateTimeField.Settings
{
public class DateTimeFieldEditorEvents : ContentDefinitionEditorEventsBase
{

public override IEnumerable < TemplateViewModel >
PartFieldEditor(ContentPartFieldDefinition definition)
{
if (definition.FieldDefinition.Name == " DateTimeField " )
{
var model
= definition.Settings.GetModel < DateTimeFieldSettings > ();
yield return DefinitionTemplate(model);
}
}

public override IEnumerable < TemplateViewModel > PartFieldEditorUpdate(
ContentPartFieldDefinitionBuilder builder, IUpdateModel updateModel)
{
var model
= new DateTimeFieldSettings();
if (updateModel.TryUpdateModel(
model,
" DateTimeFieldSettings " , null , null ))
{
builder.WithSetting(
" DateTimeFieldSettings.Display " ,
model.Display.ToString());
}

yield return DefinitionTemplate(model);
}
}
}
这个类似与一个driver,但是是field settings。第一个方法获得设置并且决定展现的模板,第二个方法从提交窗口中更新模型值。

生成目录Views\DefinitionTemplates,添加字段的编辑摸板文件DateTimeFieldSettings.cshtml:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
@model CustomFields.DateTimeField.Settings.DateTimeFieldSettings
@using CustomFields.DateTimeField.Settings;

< fieldset >
< label for = " @Html.FieldIdFor(m => m.Display) "
class = " forcheckbox " > @T( " Display options " ) </ label >
< select id = " @Html.FieldIdFor(m => m.Display) "
name
= " @Html.FieldNameFor(m => m.Display) " >
@Html.SelectOption(DateTimeFieldDisplays.DateAndTime,
Model.Display
== DateTimeFieldDisplays.DateAndTime,
T(
" Date and time " ).ToString())
@Html.SelectOption(DateTimeFieldDisplays.DateOnly,
Model.Display
== DateTimeFieldDisplays.DateOnly,
T(
" Date only " ).ToString())
@Html.SelectOption(DateTimeFieldDisplays.TimeOnly,
Model.Display
== DateTimeFieldDisplays.TimeOnly,
T(
" Time only " ).ToString())
</ select >

@Html.ValidationMessageFor(m
=> m.Display)

</ fieldset >

更新项目文件

打开项目文件CustomFields.csproj:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
< Compile Include = " Drivers\DateTimeFieldDriver.cs " />

< Compile Include = " Fields\DateTimeField.cs " />

< Compile Include = " Settings\DateTimeFieldEditorEvents.cs " />

< Compile Include = " Settings\DateTimeFieldSettings.cs " />

< Compile Include = " ViewModels\DateTimeFieldViewModel.cs " />

添加样式

Create a Styles directory and create the following datetime.css:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
html.dyn label.forpicker {
display
: none ;
}

html.dyn input.hinted
{
color
: #ccc ;
font-style
: italic ;
}
.date input
{
width
: 10em ;
}
.time input
{
width
: 6em ;
}

使用字段

为了能够使用心得字段,首先必须打开Orchard.ContentTypes功能,还需要打开DateTimeField 功能。

201102171223148684.png201102171223153984.png

201102171223151999.png201102171223152522.png

参考:Writing a content field http://orcharddatetimefield.codeplex.com/

推荐:你可能需要的在线电子书201102171223158901.gif 

我的新浪围脖: http://t.sina.com.cn/openexpressapp

欢迎转载,转载请注明:转载自周金根 [ http://zhoujg.cnblogs.com/ ]

转载于:https://www.cnblogs.com/zhoujg/archive/2011/02/17/1956817.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值