Views: 2297
Number of votes: 0
Average rating:

Settings for properties

Background

One of the top developer feature request I have heard during my years at EPiServer has been to be able to store settings for a property. In EPiServer CMS 5 an administrator has had the possibility to select which plugins should be available for the built in editor. This feature has been only been available for longstring/xhtmlstring properties and it has not been able for developers to add their own settings for their custom properties.

Note: This feature should not be mistaken with “Properties for Properties”, ie to be able to save down additional properties on your custom property class for each page instance.

Whats new in EPiServer CMS 6

In EPiServer CMS 6 we are working on implementing support for the TinyMCE editor. This editor will replace the current editor as the default editor though you still have the option to use the old editor. You can even use the different editors for different properties in you like that. This is described more in my previous blog post Setting up multiple property controls for a property. As TinyMCE needs to be able to store different settings for plugins etc and we still need the support for settings for the old editor we decided to implement settings for properties for all kind of properties.

How do I add my own property settings?

Property settings are added to a property by adding attributes to either your property class or your property control class:

[PropertySettings(typeof(Settings), true)]
public class PropertyXhtmlStringControl :

PropertyLongStringControlBase

The settings class must implement IPropertySettings and might look something like this:

[PropertySettingsUI(AdminControl = typeof(SettingsUISample))]
public class SamplePropertySettings : IPropertySettings
{
public int Width { get; set; }

public IPropertySettings GetDefaultValues()
{
return new SamplePropertySettings() {Width = 200};
}
}

You might have noticed that this class also specifies a similar attribute. The PropertySettingsUI defines the class that is used to edit the settings. This class must inherit  The System.Web.UI.WebControls.Control class as well as implementing the IPropertySettingsUI interface. Or you can just inherit from the PropertySettingsUIBase and implement the abstract methods. It’s also possible to specify the url to a user control through either the Url, UrlFromUi or UrlFromUtil property. This user control needs to either implement IPropertySettingsUI or inherrit PropertySettingsUserControlBase.

How do I access the settings object?

PropertyData has got a new Property:

public PropertySettingsContainer SettingsContainer

It will also have a new method:

public IPropertySettings GetSetting(Type settingsType)

The PropertySettingsContainer might hold settings for both the PropertyData-derived object as well as settings for all configured property controls for the property. With the GetSetting-method you are able to fetch the settings object that you are interested in. For a property control for instance, you are able to fetch both your own settings as well as the settings for the PropertyData-object. It’s even possible to get the settings for another Property Control that is registered for the property as long as you know the type name for the controls settings object.  Here is an example that shows how to load a settings object of the type “Settings” when loading the TinyMCE editor:

public override void CreateEditControls()
{
Settings settings =
(Settings)PropertyData.GetSetting(typeof(Settings));

EditControl = new Editor.TinyMCE.Editor(settings);

An entire code sample

Below is a code sample that describes how to implement the different parts needed to get use of setting for properties. This includes the property control that uses the settings, a sample settings class and a class that creates the admin user interface for the settings.

using System.Web.UI;
using EPiServer.Web.PropertyControls;
using System.Web.UI.WebControls;
using EPiServer.Core.PropertySettings;
namespace CodeSamples
{
    [PropertySettings(typeof(SamplePropertySettings), true)]
    public class SamplePropertyControlWithSettings : PropertyTextBoxControlBase
    {
        protected override void SetupEditControls()
        {
            EditControl.Text = ToString();
            SamplePropertySettings settings = (SamplePropertySettings)PropertyData.GetSetting(typeof(SamplePropertySettings));
            EditControl.Width = settings.Width;
        }
    }
    /// <summary>
    /// Example of a settings class. Needs to inherit from <see cref="IPropertySettings"/>.
    /// The easiest way is to inherit from PropertySettingsBase.
    /// </summary>
    [PropertySettingsUI(AdminControl = typeof(SettingsUISample))]
    public class SamplePropertySettings : PropertySettingsBase
    {
        public int Width { get; set; }
        /// <summary>
        /// Gets the default values. for the setting this is used when nothing 
        /// is specified in the settings store either locally or globally.
        /// </summary>
        public override IPropertySettings GetDefaultValues()
        {
            return new SamplePropertySettings() { Width = 200 };
        }
    }
    /// <summary>
    /// Used to render a UI for editing the settings in the admin UI.
    /// Needs to be in the inherit from <see cref="Control"/> and implement <see cref="IPropertySettingsUI"/>.
    /// Most easily accomplished using <see cref="PropertySettingsControlBase"/>
    /// </summary>
    public class SettingsUISample : PropertySettingsControlBase
    {
        private TextBox _widthInput;
        #region IPropertySettingsUI Members
        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            _widthInput = new TextBox { ID = "WidthValue" };
            Label label = new Label { Text = "Width", AssociatedControlID = "WidthValue" };
            Controls.Add(label);
            Controls.Add(_widthInput);
        }
        public override void LoadSettingsUI(IPropertySettings propertySettings)
        {
            EnsureChildControls();
            _widthInput.Text = ((SamplePropertySettings)propertySettings).Width.ToString();
        }
        public override void UpdateSettings(IPropertySettings propertySettings)
        {
            EnsureChildControls();
            ((SamplePropertySettings)propertySettings).Width = int.Parse(_widthInput.Text);
        }
        #endregion
    }
}

To test this sample property control I have added a configuration setting to use my property control as the ui control for the built in property PropertyString.

<add type="EPiServer.Core.PropertyControlClassFactory, 
EPiServer" id="PropertyControlFactory">
<register type="EPiServer.Core.PropertyString, EPiServer"
mappedType="CodeSamples.SamplePropertyControlWithSettings,
EPiServer.Templates.Public" />
</add>

PropertySettingsAdminUI

Figure 1: A screenshot of how the admin ui looks like when editing a page type property of type PropertyString. Note the tabbed ui where the custom settings tab is where your property settings ui will be displayed.

CustomPropertyEditModeExample

Figure 2: A screenshot of the actual property in edit mode(with the width set to 400):

Validation of input values

If you need to validate any input values you should add validation controls to your settings ui control. When the save button is pressed the page will call Page.Validate() and any validation messages will show up at the top of the dialog.

ValidationExample

Figure 3: An example of using validation controls in the property settings ui.

Using global settings

As you might have noticed in the settings admin UI there is a option to “Use global settings”. This can either be the default setting which results in a call to the method “GetDefaultSettings” for the settings class or a global settings object. These are defined per property type (PropertyString, PropertyNumber, MyCustomProperty etc). It’s also possible to assign the “default settings” to use one of the created global settings objects instead of the code default settings.

When defining settings for a page type property you can either use the default settings, a global setting object or define custom settings that will only affect the current property. Often it might be enough to define your default settings and add a couple of global settings which you point to for the properties that you want to differ from the standard settings.

An example might be the editor settings for a PropertyXhtmlString. Default settings might be to have an editor with all the default plug-ins enabled. To be able to have some properties that use a more basic editor you create a global settings object with a few plug-ins that you want to use. Then you set your properties that want to have the locked down editor to use this global settings object.

GlobalSettingsUI

Figure 4: A screenshot showing the global settings UI including a popup window to add a new global setting.

Oct 15, 2009

Guest
(By Guest, 10/12/2010 12:33:26 PM)

Very cool! Something that I'm sure many will appreciate.
/ Frederik Vig

Guest
(By Guest, 10/12/2010 12:33:28 PM)

Linus, this looks really great!! This will make it much easier to create better editor experiences. At least when I look at it from my developer eyes! I must say however that the interface for editing the settings look a bit confusing, but I'm sure it will get some UX touches before release! :)
/ Henrik Nyström

Guest
(By Guest, 10/12/2010 12:33:29 PM)

Loving it!!!
/ Allan

Guest
(By Guest, 10/12/2010 12:33:30 PM)

Great post and feature! Trying to follow your sample and using a PropertyPageReferenceControl as one of the setting controls. I can't get the set values in UpdateSettings. Can you provide a sample?
/ Thomas Haug, Gazette as

Guest
(By Guest, 10/12/2010 12:33:31 PM)

Hi! Have you tried using an InputPageReference control instead?
/ Linus Ekström (linuse)

Guest
(By Guest, 10/12/2010 12:33:32 PM)

Hi Linus Have you had any issues with the values not persisting between project builds? Every time i rebuild it clears the value in the custom settings
/ Ben Edwards

Guest
(By Guest, 10/12/2010 12:33:36 PM)

Hi! I know that the dds, which the values are saved in, might have a hard time mapping changed properties for a class. In this case you need to call remap for the type (or just clear any existing values for the type). If you just add new properties this should not be a problem but if you change the type of a property in your settings class this might be an issue.
/ Linus Ekström

Please login to comment.