Orchard Harvest: Shapes Session

by Oliver 14. June 2013 18:09

These are session notes, so they might not adhere to the standards of a complete blog post, but there's a bunch of inspiring info that I had to get out of my head…

Shapes – Overview

What are they

  • dynamic data model
    • can be updated at runtime
  • replaces static(ally typed) view models

Creating Shapes

  • Never instantiate Shape directly
    • it won't trigger the related events
  • in code, use an IShapeFactory dependency
    • IShape Create(string shapeType)
  • in Orchard views, use New
      - New is just an IShapeFactory cast to dynamic
      - New.Product -> IShapeFactory.Create("Product")

Rendering Shapes

  • use well-named file templates
  • use shape methods
    • any method in class inheriting from IDependency with the [Shape] attribute
  • future: dynamic shapes to come, e.g. from DB (by Piotr Szmyd)
  • refer to IDisplayHelperFactory and IDisplayHelper for more detailed info

Advanced Uses of Shapes

If you're just starting with Orchard Shapes, I recommend you to skip this section for now ;-)

Creating Strongly Typed Shapes

  • in your ContentDriver, when creating a Shape, you can do:
   1: protected override DriverResult Display(EntryPart part, string displayType, dynamic shapeHelper) {
   2:     return ContentShape("Parts_Common_Body" /* Placement Key */,
   3:                         () => shapeHelper.Parts_Common_Body(Html: someHtml));
   4: }

becomes:

   1: public class ConcreteType : Shape {
   2:     public string Html { get; set; }
   3: }
   4:  
   5: protected override DriverResult Display(EntryPart part, string displayType, dynamic shapeHelper) {
   6:     var shape = (ConcreteType) shapeHelper.Parts_Common_Body(typeof(ConcreteType))
   7:     shape.Html = someHtml;
   8:     return ContentShape("Parts_Common_Body" /* Placement Key */,
   9:                         () => shape);
  10: }

And then in your template, you can actually define your @model to be of type ConcreteType:

   1: @model My.Namespace.ConcreteType
   2:  
   3: @Display(Model.Html)

Shape Events

We have different extension points to hook into the shape rendering process:

  • IShapeDisplayEvent
    • intercept all shape Display events
  • ShapeMetadata
    • intercept a specific shape's Display events
  • IShapeTableProvider
    • configured at discovery time, for a specific type
    • hook into events other than Display

Order of invocation of the different event handlers:

  • Displaying
    1. ShapeDisplayEvents
    2. ShapteTableProvider
    3. ShapeMetadata
  • Display
    1. Set Metadata.ChildContent
    2. Shape is rendered if ChildContent not set (open e.g. for Caching)
    3. Wrappers are rendered in order, from Metadata.ChildContent, e.g. Document.cshtml
  • Displayed
    1. ShapeDisplayEvents
    2. ShapteTableProvider
    3. ShapeMetadata

Shape Morphing

  • change the Metadata.Type of a Shape before rendering
  • render the same Shape again using a different template
  • see the MenuItem template for an example

Shape Relocation

The idea here is to add a Shape to a different part of the page than where your current ContentItem is rendering.

In your view, just use:

   1: @Display(Model.MyTitle)

Now, in your placement.info file, write:

   1: <Match ContentType="Page" DisplayType="Detail"> 
   2:     <Place Parts_Title="MyTitle:5" />
   3: </Match>

This will display your Title shape (possibly) a second time.

Comments (2) -

Gabe United States
9/3/2013 2:31:18 AM #

Thanks so much for posting this!  I had a scenario in which I needed to generate a shape in a controller child action and render it as a partial view.  The information in this post, specifically using IShapeFactory.Create() was critical to solving this problem.

Raven Bredlow United States
6/4/2015 3:13:23 PM #

Terrific post however , I was wondering if you could write a litte more on this topic? I'd be very grateful if you could elaborate a little bit further. Cheers!

Pingbacks and trackbacks (1)+

Comments are closed

About Oliver

shades-of-orange.com code blog logo I build web applications using ASP.NET and have a passion for javascript. Enjoy MVC 4 and Orchard CMS, and I do TDD whenever I can. I like clean code. Love to spend time with my wife and our children. My profile on Stack Exchange, a network of free, community-driven Q&A sites

About Anton

shades-of-orange.com code blog logo I'm a software developer at teamaton. I code in C# and work with MVC, Orchard, SpecFlow, Coypu and NHibernate. I enjoy beach volleyball, board games and Coke.