首先Orchard是一个建立在ASP.NET MVC框架上的CMS应用框架。Orchard在呈现内容的时候也遵循MVC的规律,也是通过Controller来处理Url请求并决定用那个View来呈现那种Model。不过这个Model就比较有讲究了,因为在Orchard中,一个页面上呈现的数据可能是多种多样的,有文章、有评论,有博客等等。而且这些数据都是可以通过后台设置任意组合的,也就是说我们不可能为每一个页面都创建一个类型的Model。那么在Orchard中是如何解决这一问题的呢?Orchard引入了形状(Shape)的概念,一个形状是一个动态类型的数据。引入形状的目的是为了取代原有静态的ASP.NET MVC视图的数据模型(Model),让数据模型的数据类型可以在运行时更改。这样就可以很好的解决Orchard需要处理多种不可预知的数据类型问题。
var shapeType = shapeName.Metadata.Type;
protected override DriverResult Display(
    MapPart part, string displayType, dynamic shapeHelper)
{
return ContentShape("Parts_Map",
                     () => shapeHelper.Parts_Map(
                           Longitude: part.Longitude, 
                           Latitude: part.Latitude));
}
using Maps.Models;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
namespace Maps.Drivers
{
    public class MapPartDriver : ContentPartDriver<MapPart>
    {
        protected override DriverResult Display(
            MapPart part, string displayType, dynamic shapeHelper)
        {
            return ContentShape("Parts_Map",
                                () => shapeHelper.Parts_Map(
                                      Longitude: part.Longitude, 
                                      Latitude: part.Latitude));
        }
        //GET
        protected override DriverResult Editor(
            MapPart part, dynamic shapeHelper)
        {
            return ContentShape("Parts_Map_Edit",
                                () => shapeHelper.EditorTemplate(
                                      TemplateName: "Parts/Map", 
                                      Model: part));
        }
        //POST
        protected override DriverResult Editor(
            MapPart part, IUpdateModel updater, dynamic shapeHelper)
        {
            updater.TryUpdateModel(part, Prefix, null, null);
            return Editor(part, shapeHelper);
        }
    }
}
标记了Get的Editor方法使用ContentShape去创建一个形状用于编辑模板。在这个案例中,形状类型名称是Parts_Map_Edit并且shapeHelper对象创建了一个EditorTemplate的形状。这是一个特殊的形状,它有一个模板名称属性和一个Model属性。模板名称属性指定了一个模板的部分路径,在这个案例中,“Parts/Map”将使Orchard在Views/EditorTemplates/Parts/Map.cshtml路径中查找相应的编辑模板。Model属性设置了这个模板所用到的数据。
下表总结了形状类型和模板的命名规则:
| Applied To | Shape Naming Convention | Shape Type Example | Template Example | 
|---|---|---|---|
| Content shapes | Content__[ContentType] | Content__BlogPost | Content-BlogPost | 
| Content shapes | Content__[Id] | Content__42 | Content-42 | 
| Content shapes | Content__[DisplayType] | Content__Summary | Content.Summary | 
| Content shapes | Content_[DisplayType]__[ContentType] | Content_Summary__BlogPost | Content-BlogPost.Summary | 
| Content shapes | Content_[DisplayType]__[Id] | Content_Summary__42 | Content-42.Summary | 
| Content.Edit shapes | Content_Edit__[DisplayType] | Content_Edit__Page | Content-Page.Edit | 
| Content Part templates | [ShapeType]__[Id] | Parts_Common_Metadata__42 | Parts/Common.Metadata-42 | 
| Content Part templates | [ShapeType]__[ContentType] | Parts_Common_Metadata__BlogPost | Parts/Common.Metadata-BlogPost | 
| Field templates | [ShapeType]__[FieldName] | Fields_Common_Text__Teaser | Fields/Common.Text-Teaser | 
| Field templates | [ShapeType]__[PartName] | Fields_Common_Text__TeaserPart | Fileds/Common.Text-TeaserPart | 
| Field templates | [ShapeType]__[ContentType]__[PartName] | Fields_Common_Text__Blog__TeaserPart | Fields/Common.Text-Blog-TeaserPart | 
| Field templates | [ShapeType]__[PartName]__[FieldName] | Fields_Common_Text__TeaserPart__Teaser | Fields/Common.Text-TeaserPart-Teaser | 
| Field templates | [ShapeType]__[ContentType]__[FieldName] | Fields_Common_Text__Blog__Teaser | Fields/Common.Text-Blog-Teaser | 
| Field templates | [ShapeType]__[ContentType]__[PartName]__[FieldName] | Fields_Common_Text__Blog__TeaserPart__Teaser | Fields/Common.Text-Blog-TeaserPart-Teaser | 
| LocalMenu | LocalMenu__[MenuName] | LocalMenu__main | LocalMenu-main | 
| LocalMenuItem | LocalMenuItem__[MenuName] | LocalMenuItem__main | LocalMenuItem-main | 
| Menu | Menu__[MenuName] | Menu__main | Menu-main | 
| MenuItem | MenuItem__[MenuName] | MenuItem__main | MenuItem-main | 
| Resource | Resource__[FileName] | Resource__flower.gif | Resource-flower.gif | 
| Style | Style__[FileName] | Style__site.css | Style-site.css | 
| Widget | Widget__[ContentType] | Widget__HtmlWidget | Widget-HtmlWidget | 
| Widget | Widget__[ZoneName] | Widget__AsideSecond | Widget-AsideSecond | 
| Zone | Zone__[ZoneName] | Zone__AsideSecond | Zone-AsideSecond | 
<img alt="Location" border="1" src="http://maps.google.com/maps/api/staticmap? 
     &zoom=14
     &size=256x256
     &maptype=satellite&markers=color:blue|@Model.Latitude,@Model.Longitude
     &sensor=false" />
@model Maps.Models.MapPart
<fieldset>
    <legend>Map Fields</legend>
            
    <div class="editor-label">
        @Html.LabelFor(model => model.Longitude)
    </div>
    <div class="editor-field">
        @Html.TextBoxFor(model => model.Latitude)
        @Html.ValidationMessageFor(model => model.Latitude)
    </div>
            
    <div class="editor-label">
        @Html.LabelFor(model => model.Longitude)
    </div>
    <div class="editor-field">
        @Html.TextBoxFor(model => model.Longitude)
        @Html.ValidationMessageFor(model => model.Longitude)
    </div>
            
</fieldset>
更多关于模板和Razor语法的信息,可查看《Template Files and their Locations》。
public class DateTimeShapes : IDependency {
    private readonly IClock _clock;
    public DateTimeShapes(IClock clock) {
        _clock = clock;
        T = NullLocalizer.Instance;
    }
    public Localizer T { get; set; }
    [Shape]
    public IHtmlString DateTimeRelative(HtmlHelper Html, DateTime dateTimeUtc) {
        var time = _clock.UtcNow - dateTimeUtc;
        if (time.TotalDays > 7)
            return Html.DateTime(dateTimeUtc, T("‘on‘ MMM d yyyy ‘at‘ h:mm tt"));
        if (time.TotalHours > 24)
            return T.Plural("1 day ago", "{0} days ago", time.Days);
        if (time.TotalMinutes > 60)
            return T.Plural("1 hour ago", "{0} hours ago", time.Hours);
        if (time.TotalSeconds > 60)
            return T.Plural("1 minute ago", "{0} minutes ago", time.Minutes);
        if (time.TotalSeconds > 10)
            return T.Plural("1 second ago", "{0} seconds ago", time.Seconds);
        return T("a moment ago");
    }
}
原文:http://www.cnblogs.com/qq260250932/p/5880305.html