Asp.net mvc 3 如何在Orchard编辑器中为datetime字段使用DateTimePicker控件(不添加datetimefieldpart)?

Asp.net mvc 3 如何在Orchard编辑器中为datetime字段使用DateTimePicker控件(不添加datetimefieldpart)?,asp.net-mvc-3,razor,editor,orchardcms,datetimepicker,Asp.net Mvc 3,Razor,Editor,Orchardcms,Datetimepicker,我知道Orchard中内置了DateTime字段,我知道可以通过将DataTimeFieldPart添加到我的自定义部分来使用它。 但我的datetime字段属于“事件部分记录”实体,我希望它们存储在一个表中。 我面临的问题是自定义部件的编辑器视图-我的datetime属性呈现为文本输入,但我希望它至少呈现为jquery timepicker或datetime类型的输入 是否有必要添加所有datetime属性,如单独的datetime部分? 如我所见,使用datetime选择器的唯一方法是手动将

我知道Orchard中内置了DateTime字段,我知道可以通过将DataTimeFieldPart添加到我的自定义部分来使用它。 但我的datetime字段属于“事件部分记录”实体,我希望它们存储在一个表中。 我面临的问题是自定义部件的编辑器视图-我的datetime属性呈现为文本输入,但我希望它至少呈现为jquery timepicker或datetime类型的输入

是否有必要添加所有datetime属性,如单独的datetime部分? 如我所见,使用datetime选择器的唯一方法是手动将其添加到编辑器视图。对我来说这很奇怪,因为Orchard在datetime部分提供了datetime选择器功能

我想我错过了一些思想上的共识

        //Event Type
        SchemaBuilder.CreateTable("EventPartRecord",
            table => table
                .ContentPartRecord()
                .Column<string>("Name")
                .Column<DateTime>("StartDateTime")
                .Column<DateTime>("PlanedEndDateTime", c=>c.Nullable())
                .Column<DateTime>("EndDateTime", c => c.Nullable())
                .Column<string>("EventRules")
                .Column<string>("Comment")
                .Column<bool>("IsFinished")
                .Column<int>("CompetitionPartRecord_Id")
            );

        ContentDefinitionManager.AlterPartDefinition("EventPart",
            builder => builder.Attachable()
                .WithField("Competitors",f => f
                .OfType("ContentPickerField")
                .WithSetting("Multiple","true"))
                );
//事件类型
SchemaBuilder.CreateTable(“EventPartRecord”,
表=>表
.ContentPartRecord()
.栏(“名称”)
.列(“StartDateTime”)
.Column(“PlanedEndDateTime”,c=>c.Nullable())
.Column(“EndDateTime”,c=>c.Nullable())
.栏(“事件规则”)
.栏(“评论”)
.列(“已完成”)
.栏(“竞争部分记录\u Id”)
);
ContentDefinitionManager.AlterPartDefinition(“EventPart”,
builder=>builder.Attachable()
.WithField(“竞争对手”,f=>f
.of类型(“ContentPickerField”)
.使用(“多重”、“真实”))
);
以下是我的看法:

    <div class="editor-label">
        @Html.LabelFor(model => model.PlanedEndDateTime)
    </div>
<div class="editor-field">
    @Html.EditorFor(model => model.PlanedEndDateTime)
    @Html.ValidationMessageFor(model => model.PlanedEndDateTime)
</div>

@LabelFor(model=>model.PlanedEndDateTime)
@EditorFor(model=>model.PlanedEndDateTime)
@Html.ValidationMessageFor(model=>model.PlanedEndDateTime)

不需要甚至不可能将所有datetime属性添加为部分:一个类型上只能存在给定类型的一个部分。不过,您可以通过字段来完成


要在您自己的部件中重现日期字段的UI,您需要做的是在您自己的部件模板中重现它们使用的模板和脚本。

使用Orchard的DateTime编辑器实际上是可能的(我的Orchard版本是1.10.1),但它需要大量自定义代码。我们开始吧

  • EventPartRecordclass

    public class EventPartRecord : Orchard.ContentManagement.Records.ContentPartRecord
    {
      // DateTime value as UTC to use Orchard convention (see CommonPart table) and to be compatible with projections
      // (date/time tokens work with UTC values, see https://github.com/OrchardCMS/Orchard/issues/6963 for a related issue)  
      public virtual System.DateTime? StartDateTimeUtc { get; set; }
    
      ...
    }
    
    public class EventPart : Orchard.ContentManagement.ContentPart<EventPartRecord>
    {
      // public
        public System.DateTime? StartDateTimeUtc 
        { 
          get { return Retrieve(r => r.StartDateTimeUtc); }
          set { Store(r => r.StartDateTimeUtc, value); }
        }
    
        public System.DateTime StartDateTime
        { 
          get
          {
            var v = ValidFromUtc;
    
            if (v.HasValue)
              return DateLocalizationServices.ConvertToSiteTimeZone(v.Value);
            else
              return null;
          }
        }
    
        // This property is needed to render Orchard`s date time editor correctly
        [System.ComponentModel.DataAnnotations.Display(Name="Start date time")]
        public Orchard.Core.Common.ViewModels.DateTimeEditor StartDateTimeProxy
        { 
          get
          {
            var v = StartDateTime;
            var lDateLocalizationOptions = new Orchard.Localization.Models.DateLocalizationOptions {EnableCalendarConversion = false, EnableTimeZoneConversion = false};
    
            return new Orchard.Core.Common.ViewModels.DateTimeEditor {ShowDate = true, ShowTime = true,
              Date = v.HasValue ? DateLocalizationServices.ConvertToLocalizedDateString(v.Value, lDateLocalizationOptions) : "",
              Time = v.HasValue ? DateLocalizationServices.ConvertToLocalizedTimeString(v.Value, lDateLocalizationOptions) : ""};
          }
    
          set
          {
            ValidFromUtc = CreateActualPropertyValue(value, "ValidFromProxy");
          }
        }
    
        ...
    
        public Orchard.Localization.Localizer T { get; set; }
        public Orchard.ContentManagement.IUpdateModel Updater { get; set; }
        public Orchard.Localization.Services.IDateLocalizationServices DateLocalizationServices { get; set; }
    
      // private
        private System.DateTime? CreateActualPropertyValue(Orchard.Core.Common.ViewModels.DateTimeEditor aProxyPropertyValue, string aProxyPropertyName)
        { 
          System.DateTime? v = null;
    
          // the following date/time handling is based on Orchard.Fields.Drivers.DateTimeFieldDriver
          bool lHasDate = !string.IsNullOrEmpty(aProxyPropertyValue.Date);
          bool lHasTime = !string.IsNullOrEmpty(aProxyPropertyValue.Time);
          var lPropertyName = T(this.GetPropertyAttribute<System.ComponentModel.DataAnnotations.DisplayAttribute>(aProxyPropertyName).Name);
    
          if (lHasDate && lHasTime)
          {
            try
            {
              v = DateLocalizationServices.ConvertFromLocalizedString(aProxyPropertyValue.Date, aProxyPropertyValue.Time, 
                new Orchard.Localization.Models.DateLocalizationOptions {EnableTimeZoneConversion = true});
            }
            catch
            {
              Updater.AddModelError(PartDefinition.Name + "." + aProxyPropertyName, T("{0} could not be parsed as a valid date and time.", lPropertyName));
            }
          }
          else
          {
            if (!lHasDate && lHasTime)
              Updater.AddModelError(PartDefinition.Name + "." + aProxyPropertyName, T("{0} requires a date.", lPropertyName));
            else
            if (lHasDate && !lHasTime)
              Updater.AddModelError(PartDefinition.Name + "." + aProxyPropertyName, T("{0} requires a time.", lPropertyName));
            else
            {
              // consider both fields empty as "no date time selection",
              // if property should be required add [System.ComponentModel.DataAnnotations.Required] to actual property as strangely adding it to proxy property does not work
            }
          }
    
          return v;
        }
    }
    
    public class EventPartDriver : Orchard.ContentManagement.Drivers.ContentPartDriver<EventPart>
    {
      // public
        public ValidityPartDriver(Orchard.Localization.Services.IDateLocalizationServices aDateLocalizationServices)
        {
          T = Orchard.Localization.NullLocalizer.Instance;
    
          mDateLocalizationServices = aDateLocalizationServices;
        }
    
        public Orchard.Localization.Localizer T { get; set; }
    
      // protected
        // GET
        protected override Orchard.ContentManagement.Drivers.DriverResult Editor(EventPart aPart, dynamic aShapeHelper)
        {
          // first, set properties which are required by the code that returns part property values for the view
          aPart.DateLocalizationServices = mDateLocalizationServices;
    
          return ContentShape("Parts_Event_Edit", () => aShapeHelper.EditorTemplate(TemplateName: "Parts/Event", Model: aPart, Prefix: Prefix));
        }
    
        // POST
        protected override Orchard.ContentManagement.Drivers.DriverResult Editor(EventPart aPart,
          Orchard.ContentManagement.IUpdateModel aUpdater, dynamic aShapeHelper)
        {
          // first, set properties which are required by the code that handles part property updates executed by aUpdater.TryUpdateModel()
          aPart.T = T;
          aPart.Updater = aUpdater;
          aPart.DateLocalizationServices = mDateLocalizationServices;
    
          aUpdater.TryUpdateModel(aPart, Prefix, null, null);
    
          return Editor(aPart, aShapeHelper);
        }
    
      // private
        private Orchard.Localization.Services.IDateLocalizationServices mDateLocalizationServices;
    }
    
  • 事件部分

    public class EventPartRecord : Orchard.ContentManagement.Records.ContentPartRecord
    {
      // DateTime value as UTC to use Orchard convention (see CommonPart table) and to be compatible with projections
      // (date/time tokens work with UTC values, see https://github.com/OrchardCMS/Orchard/issues/6963 for a related issue)  
      public virtual System.DateTime? StartDateTimeUtc { get; set; }
    
      ...
    }
    
    public class EventPart : Orchard.ContentManagement.ContentPart<EventPartRecord>
    {
      // public
        public System.DateTime? StartDateTimeUtc 
        { 
          get { return Retrieve(r => r.StartDateTimeUtc); }
          set { Store(r => r.StartDateTimeUtc, value); }
        }
    
        public System.DateTime StartDateTime
        { 
          get
          {
            var v = ValidFromUtc;
    
            if (v.HasValue)
              return DateLocalizationServices.ConvertToSiteTimeZone(v.Value);
            else
              return null;
          }
        }
    
        // This property is needed to render Orchard`s date time editor correctly
        [System.ComponentModel.DataAnnotations.Display(Name="Start date time")]
        public Orchard.Core.Common.ViewModels.DateTimeEditor StartDateTimeProxy
        { 
          get
          {
            var v = StartDateTime;
            var lDateLocalizationOptions = new Orchard.Localization.Models.DateLocalizationOptions {EnableCalendarConversion = false, EnableTimeZoneConversion = false};
    
            return new Orchard.Core.Common.ViewModels.DateTimeEditor {ShowDate = true, ShowTime = true,
              Date = v.HasValue ? DateLocalizationServices.ConvertToLocalizedDateString(v.Value, lDateLocalizationOptions) : "",
              Time = v.HasValue ? DateLocalizationServices.ConvertToLocalizedTimeString(v.Value, lDateLocalizationOptions) : ""};
          }
    
          set
          {
            ValidFromUtc = CreateActualPropertyValue(value, "ValidFromProxy");
          }
        }
    
        ...
    
        public Orchard.Localization.Localizer T { get; set; }
        public Orchard.ContentManagement.IUpdateModel Updater { get; set; }
        public Orchard.Localization.Services.IDateLocalizationServices DateLocalizationServices { get; set; }
    
      // private
        private System.DateTime? CreateActualPropertyValue(Orchard.Core.Common.ViewModels.DateTimeEditor aProxyPropertyValue, string aProxyPropertyName)
        { 
          System.DateTime? v = null;
    
          // the following date/time handling is based on Orchard.Fields.Drivers.DateTimeFieldDriver
          bool lHasDate = !string.IsNullOrEmpty(aProxyPropertyValue.Date);
          bool lHasTime = !string.IsNullOrEmpty(aProxyPropertyValue.Time);
          var lPropertyName = T(this.GetPropertyAttribute<System.ComponentModel.DataAnnotations.DisplayAttribute>(aProxyPropertyName).Name);
    
          if (lHasDate && lHasTime)
          {
            try
            {
              v = DateLocalizationServices.ConvertFromLocalizedString(aProxyPropertyValue.Date, aProxyPropertyValue.Time, 
                new Orchard.Localization.Models.DateLocalizationOptions {EnableTimeZoneConversion = true});
            }
            catch
            {
              Updater.AddModelError(PartDefinition.Name + "." + aProxyPropertyName, T("{0} could not be parsed as a valid date and time.", lPropertyName));
            }
          }
          else
          {
            if (!lHasDate && lHasTime)
              Updater.AddModelError(PartDefinition.Name + "." + aProxyPropertyName, T("{0} requires a date.", lPropertyName));
            else
            if (lHasDate && !lHasTime)
              Updater.AddModelError(PartDefinition.Name + "." + aProxyPropertyName, T("{0} requires a time.", lPropertyName));
            else
            {
              // consider both fields empty as "no date time selection",
              // if property should be required add [System.ComponentModel.DataAnnotations.Required] to actual property as strangely adding it to proxy property does not work
            }
          }
    
          return v;
        }
    }
    
    public class EventPartDriver : Orchard.ContentManagement.Drivers.ContentPartDriver<EventPart>
    {
      // public
        public ValidityPartDriver(Orchard.Localization.Services.IDateLocalizationServices aDateLocalizationServices)
        {
          T = Orchard.Localization.NullLocalizer.Instance;
    
          mDateLocalizationServices = aDateLocalizationServices;
        }
    
        public Orchard.Localization.Localizer T { get; set; }
    
      // protected
        // GET
        protected override Orchard.ContentManagement.Drivers.DriverResult Editor(EventPart aPart, dynamic aShapeHelper)
        {
          // first, set properties which are required by the code that returns part property values for the view
          aPart.DateLocalizationServices = mDateLocalizationServices;
    
          return ContentShape("Parts_Event_Edit", () => aShapeHelper.EditorTemplate(TemplateName: "Parts/Event", Model: aPart, Prefix: Prefix));
        }
    
        // POST
        protected override Orchard.ContentManagement.Drivers.DriverResult Editor(EventPart aPart,
          Orchard.ContentManagement.IUpdateModel aUpdater, dynamic aShapeHelper)
        {
          // first, set properties which are required by the code that handles part property updates executed by aUpdater.TryUpdateModel()
          aPart.T = T;
          aPart.Updater = aUpdater;
          aPart.DateLocalizationServices = mDateLocalizationServices;
    
          aUpdater.TryUpdateModel(aPart, Prefix, null, null);
    
          return Editor(aPart, aShapeHelper);
        }
    
      // private
        private Orchard.Localization.Services.IDateLocalizationServices mDateLocalizationServices;
    }
    
    公共类事件部分:Orchard.ContentManagement.ContentPart
    {
    //公开的
    public System.DateTime?StartDateTimeUtc
    { 
    获取{return Retrieve(r=>r.StartDateTimeUtc);}
    设置{Store(r=>r.StartDateTimeUtc,value);}
    }
    public System.DateTime StartDateTime
    { 
    得到
    {
    var v=有效的UTC;
    如果(v.HasValue)
    return DateLocalizationServices.ConvertToSiteTimeZone(v.Value);
    其他的
    返回null;
    }
    }
    //正确呈现Orchard的日期时间编辑器需要此属性
    [System.ComponentModel.DataAnnotations.Display(Name=“开始日期时间”)]
    public Orchard.Core.Common.ViewModels.DateTimeEditor StartDateTimeProxy
    { 
    得到
    {
    var v=起始日期时间;
    var lDateLocalizationOptions=new Orchard.Localization.Models.DateLocalizationOptions{EnableCalendarConversion=false,EnableTimeZoneConversion=false};
    返回新的Orchard.Core.Common.ViewModels.DateTimeEditor{ShowDate=true,ShowTime=true,
    Date=v.HasValue?DateLocalizationServices.ConvertToLocalizedDataTestRing(v.Value,lDateLocalizationOptions):“”,
    Time=v.HasValue?DateLocalizationServices.ConvertToLocalizedTimeString(v.Value,lDateLocalizationOptions):“”;
    }
    设置
    {
    ValidFromUtc=CreateActualPropertyValue(值,“ValidFromProxy”);
    }
    }
    ...
    public Orchard.Localization.Localizer T{get;set;}
    public Orchard.ContentManagement.IUpdateModel更新程序{get;set;}
    public Orchard.Localization.Services.IDateLocalizationServices日期本地化服务{get;set;}
    //私人的
    private System.DateTime?CreateActualPropertyValue(Orchard.Core.Common.ViewModels.DateTimeEditor aProxyPropertyValue,字符串aProxyPropertyName)
    { 
    System.DateTime?v=null;
    //以下日期/时间处理基于Orchard.Fields.Drivers.DateTimeFieldDriver
    bool lHasDate=!string.IsNullOrEmpty(aProxyPropertyValue.Date);
    bool lHasTime=!string.IsNullOrEmpty(aProxyPropertyValue.Time);
    var lPropertyName=T(this.GetPropertyAttribute(aProxyPropertyName).Name);
    if(拉斯代特和拉斯代姆)
    {
    尝试
    {
    v=DateLocalizationServices.ConvertFromLocalizedString(aProxyPropertyValue.Date,aProxyPropertyValue.Time,
    新的Orchard.Localization.Models.DateLocalizationOptions{EnableTimeZoneConversion=true});
    }
    抓住
    {
    Updater.AddModelError(PartDefinition.Name+“+aProxyPropertyName,T(“{0}无法解析为有效的日期和时间。”,lPropertyName));
    }
    }
    其他的
    {
    如果(!lHasDate&&lHasTime)
    AddModelError(PartDefinition.Name+“+aProxyPropertyName,T(“{0}需要一个日期。”,lPropertyName));
    其他的
    if(lHasDate&!lHasTime)
    AddModelError(PartDefinition.Name+“+aProxyPropertyName,T(“{0}需要一个时间。”,lPropertyName));
    其他的
    {
    /将两个字段视为“无日期时间选择”,
    //如果属性是必需的,则将[System.ComponentModel.DataAnnotations.required]添加到实际属性,因为奇怪的是,将其添加到代理属性并不起作用
    }
    }
    返回v;
    }
    }
    
  • EventPartDriver

    public class EventPartRecord : Orchard.ContentManagement.Records.ContentPartRecord
    {
      // DateTime value as UTC to use Orchard convention (see CommonPart table) and to be compatible with projections
      // (date/time tokens work with UTC values, see https://github.com/OrchardCMS/Orchard/issues/6963 for a related issue)  
      public virtual System.DateTime? StartDateTimeUtc { get; set; }
    
      ...
    }
    
    public class EventPart : Orchard.ContentManagement.ContentPart<EventPartRecord>
    {
      // public
        public System.DateTime? StartDateTimeUtc 
        { 
          get { return Retrieve(r => r.StartDateTimeUtc); }
          set { Store(r => r.StartDateTimeUtc, value); }
        }
    
        public System.DateTime StartDateTime
        { 
          get
          {
            var v = ValidFromUtc;
    
            if (v.HasValue)
              return DateLocalizationServices.ConvertToSiteTimeZone(v.Value);
            else
              return null;
          }
        }
    
        // This property is needed to render Orchard`s date time editor correctly
        [System.ComponentModel.DataAnnotations.Display(Name="Start date time")]
        public Orchard.Core.Common.ViewModels.DateTimeEditor StartDateTimeProxy
        { 
          get
          {
            var v = StartDateTime;
            var lDateLocalizationOptions = new Orchard.Localization.Models.DateLocalizationOptions {EnableCalendarConversion = false, EnableTimeZoneConversion = false};
    
            return new Orchard.Core.Common.ViewModels.DateTimeEditor {ShowDate = true, ShowTime = true,
              Date = v.HasValue ? DateLocalizationServices.ConvertToLocalizedDateString(v.Value, lDateLocalizationOptions) : "",
              Time = v.HasValue ? DateLocalizationServices.ConvertToLocalizedTimeString(v.Value, lDateLocalizationOptions) : ""};
          }
    
          set
          {
            ValidFromUtc = CreateActualPropertyValue(value, "ValidFromProxy");
          }
        }
    
        ...
    
        public Orchard.Localization.Localizer T { get; set; }
        public Orchard.ContentManagement.IUpdateModel Updater { get; set; }
        public Orchard.Localization.Services.IDateLocalizationServices DateLocalizationServices { get; set; }
    
      // private
        private System.DateTime? CreateActualPropertyValue(Orchard.Core.Common.ViewModels.DateTimeEditor aProxyPropertyValue, string aProxyPropertyName)
        { 
          System.DateTime? v = null;
    
          // the following date/time handling is based on Orchard.Fields.Drivers.DateTimeFieldDriver
          bool lHasDate = !string.IsNullOrEmpty(aProxyPropertyValue.Date);
          bool lHasTime = !string.IsNullOrEmpty(aProxyPropertyValue.Time);
          var lPropertyName = T(this.GetPropertyAttribute<System.ComponentModel.DataAnnotations.DisplayAttribute>(aProxyPropertyName).Name);
    
          if (lHasDate && lHasTime)
          {
            try
            {
              v = DateLocalizationServices.ConvertFromLocalizedString(aProxyPropertyValue.Date, aProxyPropertyValue.Time, 
                new Orchard.Localization.Models.DateLocalizationOptions {EnableTimeZoneConversion = true});
            }
            catch
            {
              Updater.AddModelError(PartDefinition.Name + "." + aProxyPropertyName, T("{0} could not be parsed as a valid date and time.", lPropertyName));
            }
          }
          else
          {
            if (!lHasDate && lHasTime)
              Updater.AddModelError(PartDefinition.Name + "." + aProxyPropertyName, T("{0} requires a date.", lPropertyName));
            else
            if (lHasDate && !lHasTime)
              Updater.AddModelError(PartDefinition.Name + "." + aProxyPropertyName, T("{0} requires a time.", lPropertyName));
            else
            {
              // consider both fields empty as "no date time selection",
              // if property should be required add [System.ComponentModel.DataAnnotations.Required] to actual property as strangely adding it to proxy property does not work
            }
          }
    
          return v;
        }
    }
    
    public class EventPartDriver : Orchard.ContentManagement.Drivers.ContentPartDriver<EventPart>
    {
      // public
        public ValidityPartDriver(Orchard.Localization.Services.IDateLocalizationServices aDateLocalizationServices)
        {
          T = Orchard.Localization.NullLocalizer.Instance;
    
          mDateLocalizationServices = aDateLocalizationServices;
        }
    
        public Orchard.Localization.Localizer T { get; set; }
    
      // protected
        // GET
        protected override Orchard.ContentManagement.Drivers.DriverResult Editor(EventPart aPart, dynamic aShapeHelper)
        {
          // first, set properties which are required by the code that returns part property values for the view
          aPart.DateLocalizationServices = mDateLocalizationServices;
    
          return ContentShape("Parts_Event_Edit", () => aShapeHelper.EditorTemplate(TemplateName: "Parts/Event", Model: aPart, Prefix: Prefix));
        }
    
        // POST
        protected override Orchard.ContentManagement.Drivers.DriverResult Editor(EventPart aPart,
          Orchard.ContentManagement.IUpdateModel aUpdater, dynamic aShapeHelper)
        {
          // first, set properties which are required by the code that handles part property updates executed by aUpdater.TryUpdateModel()
          aPart.T = T;
          aPart.Updater = aUpdater;
          aPart.DateLocalizationServices = mDateLocalizationServices;
    
          aUpdater.TryUpdateModel(aPart, Prefix, null, null);
    
          return Editor(aPart, aShapeHelper);
        }
    
      // private
        private Orchard.Localization.Services.IDateLocalizationServices mDateLocalizationServices;
    }
    
    公共类EventPartDriver:Orchard.ContentManagement.Drivers.ContentPartDriver
    {
    //公开的
    公共ValidityPartDriver(Orchard.本地化.S