EPiServer Custom Property for Dynamic Content Plugin

We needed to give the editors a simple way of using variable amounts that could change over time inline in the text.
These amounts needed to be placed inline (RenderAsBlockElement) in the Tiny MCE text editor for example: You need to pay $1000 to us by the end of august.

The EPiServer documentation for CMS 9 on Dynamic content leaves a lot to wish for and didn’t seem to work in an pure MVC project.

The solution seemed to be to create a custom EPiServer drop down list property, (the standard ones didn’t fit the bill).
By using a custom property we could piggyback on the presentation of the control and eliminate the work of mapping our own view.

So we needed to create a Dynamic Content plugin first

The Dynamic Content Plugin uses our custom property that is a standard PropertyDropDownList but instead of getting the data from AppSettings or the property definition in Admin mode we hooked it up to properties on the startpage. Its there we will put all of our amounts, and we will isolate them using an custom tab.

Here is our Dynamic Content Plugin

[DynamicContentPlugIn(DisplayName = "Avgifter från startsidan")]

public class Amounts : DynamicContentBase, IDynamicContentView
{
public Amounts()
{
base.Properties = new PropertyDataCollection();
base.Properties.Add("Avgifter", new AmountsDropDown());

}

public virtual void Render(TextWriter writer)
{
var startPage = ContentReference.StartPage.GetPage();

writer.Write("" + startPage.Property.Get(Properties.Get("Avgifter").Value + "").Value + "");
}

public override bool RenderAsBlockElement
{
get { return false; }
}
}

Here is our Custom Property drop down plugin

[EditorHint("DropDownList")]
[Serializable]
[PropertyDefinitionTypePlugIn(DisplayName = "Avgifter från startsidan",Description = "Hämtar avgifter från startsidan")]
public class AmountsDropDown : PropertyLongString
{
public override IPropertyControl CreatePropertyControl()
{
return new AmountsDropDownControl();
}
}

///
/// PropertyDropDownListControl implementation used for rendering fields from startpage.
///

[PropertySettings(typeof(MultipleOptionsListSettings), false)]
public class AmountsDropDownControl : PropertyDropDownListControl
{
public PropertyDropDownList DropDownListValue => PropertyData as PropertyDropDownList;

public AmountsDropDown AmountsDropDown
{
get { return PropertyData as AmountsDropDown; }
}

protected override void SetupEditControls()
{
SetupDropDownList();
}

protected virtual void SetupDropDownList()
{

AddDropDownListItems();

if (DropDownListValue?.Value != null)
{
var li = EditControl.Items.FindByValue(DropDownListValue.Value + "");
if (li != null)
li.Selected = true;
}
EditControl.DataBind();
}

// This method extracts all the properties from the startpage that resides under the tab "Amounts"
protected virtual void AddDropDownListItems()
{
var startPage = ContentReference.StartPage.GetPage();

var amounts = startPage.GetOriginalType().GetProperties()
.Where(p => p.GetCustomAttributes(typeof(DisplayAttribute), true)
.OfType()
.Any(a => a.GroupName == GroupNames.Amounts));

foreach (var prop in amounts)
{
EditControl.Items.Add(new ListItem(prop.Name, prop.Name));
}
}
}

Here is the end result

Untitled

Displaying file size for your MediaData

Creating a document link as file.pdf(230kB ) may seem like a simple task…

Well now it is…

My Generic media

public class GenericMedia : MediaData
{
[CultureSpecific]
[Display( Name = "Title-text",
Description = "Ange title-text",
GroupName = SystemTabNames.Content, Order = 2)] 

public virtual String Description { get; set; }
public virtual string Copyright { get; set; }
[Editable(false)]
public virtual string FileSize { get; set; } }

Helper to get the file size


 public static string GetFileSize(GenericMedia media)
        {
            if (media != null)
            {
                using (var stream = media.BinaryData.OpenRead())
                {
                    return (stream.Length /1024)+ " kB";
                }
            }
            return string.Empty;
        }

And som magic sprinkle of events


namespace proj.Business.Initialization
{
    [InitializableModule]
    [ModuleDependency(typeof (EPiServer.Web.InitializationModule))]
    public class InitializationModule : IInitializableModule
    {
        public void Initialize(InitializationEngine context)
        {
            var eventRegistry =
            ServiceLocator.Current.GetInstance<IContentEvents>();

            eventRegistry.CreatingContent += OnCreatingContent;
            eventRegistry.SavingContent += OnSavingContent;

        }

        public void Preload(string[] parameters)
        {
        }

        public void Uninitialize(InitializationEngine context)
        {
            var eventRegistry =
            ServiceLocator.Current.GetInstance<IContentEvents>();

            eventRegistry.CreatingContent -= OnCreatingContent;
            eventRegistry.SavingContent -= OnSavingContent;

       }

        private void OnSavingContent(object sender, ContentEventArgs e)
        {
            var content = e.Content as GenericMedia;
            if (content == null)
                return;
            var fs = ContentHelpers.GetFileSize(content);
            content.FileSize = fs;
        }

        private static void OnCreatingContent(object sender, ContentEventArgs e)
        {
            var content = e.Content as GenericMedia;
            if (content == null)
                return;
            var fs = ContentHelpers.GetFileSize(content);
            content.FileSize = fs;
        }
    }
}

 

Usage


<a title="@content.Description" href="@UrlResolver.Current.GetUrl(content.ContentLink)">
@content.Name (@content.FileSize)</a>

Enjoy!