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


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

    目标

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

    生成一个模块

    codegen module CustomFields /IncludeInSolution:true

    现在在Modules目录下有一个新的目录:CustomFields,更改module.txt:

    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:

    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:

    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:

    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

    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:

    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:

    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:

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

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

    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:

    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:

    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:

    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 功能。

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

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

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

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

  • 相关阅读:
    atitit.团队建设要不要招技术储备人才的问题
    Atitit. 最佳实践 QA降低cpu占有率cpu占用太高怎么办
    Atitit.struts2体系结构大总结
    Atitit.hibernate体系结构大总结
    Atitit.软件GUI按钮与仪表盘db数据库区导入mysql sql错误的解决之道
    Atitit. Gui控件and面板程序快速启动区最佳实践Launchy ObjectDocko0g
    Atitit。团队建设管理最佳实践如何留住核心人才,防止人才流失 ??
    Atitit.ALT+TAB没反应车and 点击任务栏程序闪烁但是不能切换
    Atitit.Gui控件and面板数据库区mssql 2008 权限 配置 报表查看成员
    Atitit.故障排除系列NoClassDefFoundError NoClassDefFoundError
  • 原文地址:https://www.cnblogs.com/zhoujg/p/1956817.html
Copyright © 2020-2023  润新知