Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EPiServer 7 - Dictionary Based Custom Property Type

I have been ramping up on EPiServer 7 MVC and have gone through Joel Abrahamsson's Alloy MVC Template. After taking a look at the customized Preview Controller, which previews a block in 4 different 'sizes' it could be rendered, I had the idea to create a Property that is specific to a certain block 'size' so that the Heading Text, for example, could display different content based on the 'size' the block renders. Essentially, this would be a Dictionary where the Key is the 'size' and the Value would contain the string content.

Has anyone made such a Dictionary property?

I've tried a few approaches and have gotten stuck with each one:

  1. Custom property type / custom value type. Following this example on creating custom property types (http://joelabrahamsson.com/creating-a-custom-episerver-property-with-a-custom-class-as-value/) I've created a Custom Property Type (PropertyDicitionaryString) and Custom Value Type (DictionaryString). I can display the value fine by implementing a Display Template that recieves a Tag with the size and then rendering Model.MyDictionaryString[ViewData["Tag"] as string]. However, I havent' figured out how to get inline editing to work, as a call to @Html.EditAttributes(x => x.MyDictionaryString[ViewData["Tag"] as string]) is not supported; that method doesn't support index or method calls in the lambda expression). Anyone known how to create such an inline editor?

  2. Custom Property Type / primitive type. I reworked my Custom Property Type for above, let's call it (PropertyDictionaryStringAsPrimitive) so that the Value property returns a string. This allows me to define my model as:

    [BackingType(typeof(PropertyDictionaryStringAsPrimitive)] public virtual string SizeSpecificString{get;set;}

    I had to hack in a way for the PropertyDictionaryStringAsPrimitive to recieve the 'size' in the current rendering context when it's Value method was called to ensure it returned the correct value. I was able to do that by implementing a custom ContentDataInterceptor, which looks for calls to PropertyDictionaryStringAsPrimitive.Value and sets the Key appropriately. So now display the value works fine, but inline editing also does not quite work. When the ajax save call is made, I need to add some state information so I can tell PropertyDictionaryStringAsPrimitive which Key to use to save the changes under. Anyone know how to pass additional state information back during an inline edit ajax save request?

  3. I took a look at the [CultureSpecific] attribute. It would be interesting if I could use a similar mechanism as CultureSpecific to keep 'size' specific instances of the values. After spending some time in a decompiler trying to work out hwo CultureSpecific works its magic, I tracked the attribute to CotnentDataAttributeScanningAssigner.AssignValuesToPropertyDefinition setting the PropertyDefinitionModel.CultureSpecific flag to true, which PropertyDefinitionSynchronizer.CreatePropertyDefintion uses to set the PropertyDefintiionModel.CultureSpecificValue to an Enum. But I couldn't find how this setting influences which value gets loaded. Anyone know how to use a Property level attribute to change the Value dynamically?

like image 546
Philip Pittle Avatar asked Aug 09 '13 10:08

Philip Pittle


1 Answers

I usually avoid custom property types, I prefer sticking to custom editors (where needed) and a block property (or blocks in a content area) for the property values.

Perhaps a viable approach would be to:

1) Create a block type like SizeSpecificHeadingBlock with:

  1. A string property called Size with a SelectOne attribute configured for a SelectionFactory returning the valid size boundary options
  2. Another string property Heading for the actual heading text

Next you could add a ContentArea with AllowedTypes set to SizeSpecificHeadingBlock.

When rendering the ContentArea, you'd simply render the heading for the current size.

However, this would require editors to create one block per heading variation, which is a bit cumbersome - but you could complement this approach with a custom editor to simplify the process.

Using a native way to store property values (instead of a custom property type) makes your implementation more future-proof. Also, if your custom editor should ever fail, you can always disable it and just use the "vanilla" EPiServer UI to editor your property values.

Edit: Although currently in beta, it might be relevant to make use of PropertyList<YourCustomType> for this kind of scenario, to avoid having to create nested blocks: http://world.episerver.com/blogs/Per-Magne-Skuseth/Dates/2015/11/trying-out-propertylistt/

like image 67
Ted Nyberg Avatar answered Oct 04 '22 15:10

Ted Nyberg