Since few months PropertyList<int> property is available in EPiServer. It allows to create list of blocks. List value is serialized to JSON and stored together with Page. The property doesn’t allow to work with simple types like strings or integers. An example of string list property can be found in AlloyTech demo. Editing widget is represented by textarea, so the editor needs to know that items are separated with line breaks. For other types like numbers or dates I didn’t find the implementation. That’s why I prepared PropertyValue<int> property where T is a simple type like string, integer or date.
PropertyListValue editor

PropertyValueList architecture

I had to introduce new backing types, editor descriptors and client editing widget. For common functionality of backing types and editors descriptors I use abstract classes.


If we want to work with a new simple type we have to implement two classes. First class will inherit from PropertyValueListBackingType<T> and the second one from PropertyValueListEditorDescriptor<T>. It’s just few lines of code. For example for IList<int> the backing type implementation:

and for editor descriptor:

Nothing more. Now we can use integer list in our content model:

The full source code contains ConcreteProperties namespace with implementations for string, int and DateTime.


The PropertyValueList base backing type inherits from PropertyList<T> which inherits from PropertyJson. It means that list value will be stored in database as a JSON object.

The concrete class needs to add PropertyDefinitionTypePlugIn and EditorHint definition attributes and implement CreateSelfInstance method which returns backing type instance.


The base EditorDescriptor is responsible for creating metadata schema for single list item.
To create metadata model I used ExtensibleMetadataProvider. Then ModelMetadata has to be converted to MetadataStoreModel. The MetadataStoreModel is used on client side to build property widget. It can be created using IMetadataStoreModelCreator service.


Content model has property of type IList<T> while I had to prepare schema for type T. The ExtensibleMetadataProvider use TypeDescriptor to get information about the model type. So I prepared my own version of ExtensibleMetadataProvider which use different TypeDescriptor.
Now when ExtensibleMetadataProvider ask for type information:

PropertyListValue TypeDescirpt conversion

I change original property (Property1) type to T:

PropertyListValue TypeDescirpt return value

Client editor

Client editor (propertyValueList.CustomCollectionWidget) use MetadataTransformer to convert serialized MetadataStoreModel to component definition. The component definition is used by WidgetFactory to create editor instance. Instance is not used on the list directly. I prepared propertyValueList.CollectionItem wrapper, to add delete button and to support items sorting.

To save the value I have to collect all nested widgets values and push them to an array. And when rendering value from the server I have to create widgets for each array element.

Using list

To use the property model we have to add BackingType attribute with concreate backing type implementation. For example for string we use PropertyExtendedStringList:

PropertyListValue strings

For dates it will be rendered as list of DateTimePicker editors:


All attributes used on property will be applied when create model schema. For example if we need list of integers with values between 10 and 20 we could use range attribute:

Property int list with range attribute

The only limitation is related with UIHints. If we set the UIHint attribute on property list, EPIServer won’t find the PropertyValueListEditorDescriptor editor descriptor. That’s why I prepare custom InnerPropertyUIHint attribute. Now let say that we need list of strings, but instead of text input, the item should be rendered as textarea. We set InnerPropertyUIHint with UIHint.Textarea attribute.

and the list will use textareas as items

PropertyListValue textareas

There are much more files than on other posts, so I placed the code on Github instead of Gists