Perhaps the most central part of the EPiServer CMS is the page property framework. It allows a developer to quickly create a website, concentrate on the front-end and get a great and easy to use management system. The property framework in EPiServer has been around for as long as I can remember (that would be around the end of 2003) and from what I know, quite some time before that as well. It got a update with the release of EPiServer 5, but otherwise it really hasn’t changed much. It is so useful and such a core part of every EPiServer site that I feel that they must be in desperate need for a little attention real soon!

Read the rest of this entry »

Advertisements

With the latest versions of EPiServer, creating a custom property is not especially complex anymore and it has been covered in lots of posts. There is one aspect of custom property creation that I think is lacking and that is using a real value type. With that I mean that the Value property of that PropertyCar should return a Car object and not the base type, for instance a String if you inherit from the LongString property for example. I know that I might be a bit picky with this but it gives the property just that extra nice feel. Even EPiServer with it’s latest creation LinkCollection doesn’t do this, instead Value returns the raw data string that is stored in the database.

So how do we get that nice feel? It is a bit harder than you would expect at a first glance. I’m going to walk you through how I created a multiple page type selector who’s Value property returns a PageTypeCollection. We’re going to inherit from PropertyLongString and save the GUID of the selected page types in a comma separated string. I won’t go into any detail around how to do the standard stuff like overriding CreatePropertyControl, others have gone into details around that already.

Starting with the basics we’ll override the PropertyValueType:

public override Type PropertyValueType
{
    get { return typeof(PageTypeCollection); }
}

Since our main goal was to get the Value property to return a PageTypeCollection we need to override that. To make this easy we’ll let it be a wrapper around a separate property of PageTypeCollection type that handles the conversion to and from a string.

One key thing when working with collection is that you either need to track if the items in the collection changes or have a read-only collection with read-only items in it. The former is not always possible if you are working with a collection that you don’t have control over like in our case. The CreateGuidList and ParseGuidList are helper methods that serializes/deserializes a PageTypeCollection to the GUID string.

private PageTypeCollection _pageTypes;

public PageTypeCollection PageTypes
{
    get
    {
        if (_pageTypes == null)
        {
            _pageTypes = ParseGuidList(base.LongString);
        }
        return _pageTypes.AsReadOnly();
    }
    set
    {
        base.ThrowIfReadOnly();
        if (value == null || value.Count() == 0)
        {
            base.Clear();
        }
        else
        {
            base.Modified();
            _pageTypes = new PageTypeCollection();
            _pageTypes.AddRange(value);
            base.LongString = CreateGuidList(_pageTypes);
        }
    }
}

public override object Value
{
    get { return this.PageTypes; }
    set { this.PageTypes = value as PageTypeCollection; }
}

Then we need to ensure that if the LongString value changes or the SetDefaultValue is called, the page type property will be reloaded. If you don’t do this, using this property type for a Dynamic property will easily break inheritance. I also used the same technique in CreateWritableClone to ensure that it won’t use the same PageTypeCollection.

protected override string LongString
{
    get
    {
        return base.LongString;
    }
    set
    {
        _pageTypes = null;
        base.LongString = value;
    }
}

protected override void SetDefaultValue()
{
    base.SetDefaultValue();
    _pageTypes = null;
}

public override PropertyData CreateWritableClone()
{
    PropertyPageTypeCollection property = (PropertyPageTypeCollection)base.CreateWritableClone();
    property._pageTypes = null;
    return property;
}

One important piece in the puzzle is to override the LoadData and SaveData methods. This is because the EPiServer data access layer doesn’t actually look at the value type but at the Type property so it will expect a string. We can make it easy for ourselves and just use the Value property of the base class since this is what the LongString property uses.

public override object SaveData(PropertyDataCollection properties)
{
    return base.Value;
}

public override void LoadData(object value)
{
    base.Value = value;
}

Finally we override ParseToObject and ParseToSelf and create a new static Parse method to make the property API work more as people would expect.

public override PropertyData ParseToObject(string value)
{
    return Parse(value);
}

public override void ParseToSelf(string value)
{
    this.Value = Parse(value).Value;
}

public new static PropertyPageTypeCollection Parse(string value)
{
    PropertyPageTypeCollection types = new PropertyPageTypeCollection();
    types.PageTypes = ParseGuidList(value);
    types.IsModified = false;
    return types;
}

And that’s it! I have implemented IEnumerable<PageType> to make it even easier to use but that is not neccesary at all.

My only regret is that I haven’t found a way to make the PageTypes property writable when the property is writable, but if you have a nice solution to this I’d love to hear about it!

You can find the complete source code here: PropertyPageTypeCollection, PropertyPageTypeCollectionControl

Update: Have posted a quick update with updates to this custom property here.

Since my last blog post about my EPiServer module PageTreeIcons, a number of things have happened that I thought I share with you really quickly (its half past twelve here and I have a release to do 7am tomorrow morning).

  • Published PageTreeIcons on epicode. Everything went really smooth, easy as to add source code and wiki pages by following their instructions on how to contribute. I would recommend everyone that is working on EPiServer to dig around and see if they can’t contribute with anything there! Also big thanks to Steve Celius at for your help!
  • Then some really nice comments from one of the other guys at BV Networks, Stein-Viggo Grenersen. He also added a request to include the target page name in the LinkType handler tool tip.
  • Added target page name to the LinkType handler tool tip and released and published version 0.2 of PageTreeIcons. The EPiServer page tree didn’t want to let me add a link to the page that updated the page tree easily, so that is left for the future.
  • Another post by Stein-Viggo that included PageTreeIcons, now featured on the EPiServer Labs blogs. This time voting for me as EMVP! I am truly honored, but I myself think I need improve my visibility a bit more. But I have a ton of cool ideas for EPiServer modules to build and publish. Stay tuned!
  • Super-Viggo is on a roll, adds a Screencast of PageTreeIcons to the epicode site!
  • PageTreeIcons is now the featured module on epicode front page!
  • Finally, beeing the featured module inspired me to write up some documentation on how to configurate the PageTreeIcons module and add that to the epicode wiki as well. Next on line is a write up on how to create your own tree icon handler. My documentation skills are getting up to a state that I just can call them slightly horrible.

Presenting PageTreeIcons

April 20, 2008

Developing for EPiServer CMS 5? Ever wanted to be able to easily show all editors that a page is just a container, that the page really is a redirect to another or that a certain property is missing on a page? Or do you just want to make that page tree a little more intuative? I have a least.

Therefore I’m now presenting to you, PageTreeIcons, an easy way to show icons in the EPiServer PageTree depending on different parameters such as the one described above. It can show icons in front of the page name like the icons for the root page, start page and recycle bin or behind like the status icons (new, not visible in menu).

PageTreeIcons comes with five standard handlers that select what icon to show for a specific page. These handlers are:

  • Page type
  • Page reference
  • Link type – Shortcut, External or Fetch data.
  • Property value
  • Icon property – A property on the page has the path to the icon to use.

You can also build you own handlers by implementing a simple interface and then specify them in the configuration file.

So how do you get your hands on this PageTreeIcon thing? Well for know, leave a comment on the page and I can send you the install package, I will also contact the good people of epicode and see if I can get it published there.

If might also come back with another blog post describing how to configure this thing if there is any demand for it.

So… I poked around some more in the EPiServer interface. Theming just didn’t cut it. So I wrote an adapter that supports adding icons and ability to do changes to the page tree. Right now it has a cool setup where you can specify a ITreeIconHandler in the web.config and it lets you add whatever you want to a specific node in the page tree really easy. So far I have four default tree icon handlers setup. One that specifies an icon for a specific PageType, one for a specific PageReference, one on LinkType (think shortcut, external link, fetch data from another page) and finally one that lets you specify a page property that holds the icon path.

All to make that page tree more intuitive for the editors.Think container pages, rss feeds and various types of data pages. Here is a preview of how it looks.

PageTreeIcons

Do you have any other ideas of what you would like to put in the page tree? Got one request to be able to hide certain page types when placed in certain containers, will try that out today I think.

Played around some with a theme for the EPiServer Edit UI. Unfortunately it’s not really as themable as you would like it to be. A lot of stuff would have to be done differently in the UI to enable easy theming. More skinned controls, no inline styles to start with. A good approach when trying to create an easily themable interface is to have two themes running in parallell from the start even if you just intend to use one of them. But then you can at least make sure that you got easy access to most of the stuff.
But I guess EPiServer had their priorities elsewhere when working to release CMS 5 (with good reason!).

In the end I just ended up changing some CSS, and adding a couple of images.

EPiServer CMS - Intergen Style

Also had some more changes going. Especially one that I really liked that slimmed down the top header to half the size. The top header is really just taking up screen real estate!! But you can’t (?) do that without a small change to their Edit.Master and I really wanted to keep everything in the theme.

The other sad part is that you cannot, ASFAIK, inherit other themes in ASP.NET, so you pretty much need to copy the original one and do changes to that, so it’s going to a little bit mean when doing upgrades. When using a different themes you often end up using a lot of common resources and a simple fallback (read: cascade) structure would solve this! sometimes wonder why MS didn’t look more of how CSS works. Because a lot of the concepts there is created from the demands that designers have.

One liners

October 12, 2007

OK, can’t really take credit for this one (thx Cristian), but wanted to share a C# one liner with you. If you know me and seen my code you should know that I love those one line statements, especially for properties.

So here it is, a one line lazy load property:
private ArrayList _lazyLoadedList;
public ArrayList LazyLoadedList
{
get { return _lazyLoadedList ?? (_lazyLoadedList = new ArrayList()); }
}

And while we’re sharing, you can know that this is how my standard ViewState properties has been looking since 2.0.
public virtual string Text
{
get { return (string)(ViewState["Text"] ?? string.Empty); }
set { ViewState["Text"] = value; }
}

Damn I love that ??-operator!