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
- ShapeDisplayEvents
- ShapteTableProvider
- ShapeMetadata
- Display
- Set Metadata.ChildContent
- Shape is rendered if ChildContent not set (open e.g. for Caching)
- Wrappers are rendered in order, from Metadata.ChildContent, e.g. Document.cshtml
- Displayed
- ShapeDisplayEvents
- ShapteTableProvider
- 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.