Frederik Vig – ASP.NET developer

Follow me

Posts tagged ‘EPiServer’

EPiServer Dropdown CheckList Property

Today I wanted to create a custom property in EPiServer that uses a dropdown list where the user can select multiple options. In HTML you have the select element which when having the attribute multiple=”multiple” actually does what I want, but can get quite long if you have many options to choose from. So I ended up creating my own with the help of the jQuery plugin Dropdown Check List which transforms a HTML select element to a dropdown check list.

I started by creating four classes: CategorySettings.cs, CategorySettingsUI.cs, PropertyDropdownCheckList.cs, and PropertyDropdownCheckListControl.cs. The two classes for the settings I just copied from my previous post on custom settings, they’re used for setting a root EPiServer category to get the options from (easier to maintain than storing them in appSettings for instance).

The code for PropertyDropdownCheckList.cs and PropertyDropdownCheckListControl.cs

using System;
using EPiServer.Core;
using EPiServer.Core.PropertySettings;
using EPiServer.PlugIn;
 
namespace EPiServer.Templates.Public.CustomProperty
{
    [Serializable]
    [PageDefinitionTypePlugIn]
    [PropertySettings(typeof (CategorySettings), true)]
    public class PropertyDropdownCheckList : PropertyString
    {
        public override IPropertyControl CreatePropertyControl()
        {
            return new PropertyDropdownCheckListControl();
        }
    }
}
using System.Web.UI.WebControls;
using EPiServer.DataAbstraction;
using EPiServer.Web.PropertyControls;
 
namespace EPiServer.Templates.Public.CustomProperty
{
    public class PropertyDropdownCheckListControl : PropertyTextBoxControlBase
    {
        protected System.Web.UI.WebControls.ListBox listBox;
 
        public override bool SupportsOnPageEdit
        {
            get { return false; }
        }
 
        public PropertyDropdownCheckList CategoryCheckBoxList
        {
            get { return PropertyData as PropertyDropdownCheckList; }
        }
 
        public override void CreateEditControls()
        {
            this.listBox = new ListBox();
            listBox.SelectionMode = ListSelectionMode.Multiple;
 
            CategorySettings settings = (CategorySettings) base.PropertyData.GetSetting(typeof (CategorySettings));
 
            Category mainCategory = Category.Find(settings.RootCategory);
            var values = CategoryCheckBoxList.Value as string;
 
            foreach (Category c in mainCategory.Categories)
            {
                ListItem li = new ListItem(c.LocalizedDescription, c.Name);
 
                if (!string.IsNullOrEmpty(values))
                {
                    foreach (string value in values.Trim().Split('|'))
                    {
                        if (value == c.Name)
                        {
                            li.Selected = true;
                        }
                    }
                }
 
                listBox.Items.Add(li);
            }
 
            ApplyControlAttributes(listBox);
            Controls.Add(listBox);
        }
 
        public override void ApplyEditChanges()
        {
            string values = string.Empty;
            foreach (ListItem listItem in this.listBox.Items)
            {
                if (listItem.Selected)
                {
                    values += listItem.Value + "|";
                }
            }
 
            SetValue(values);
        }
    }
}

I now ended up being able to choose a root category under my properties settings and rendering a HTML select element with the attribute multiple set to multiple.

This is how it now looked for me in EPiServer edit mode.
Multiple select element in EPiServer edit mode

Next thing was adding the jQuery plugin and implementing the code – which also was very straight forward. I added a new method for registering my resources (CSS and JavaScript files), and a helper method for my CSS files. Here’s how PropertyDropdownCheckListControl.cs ended up looking.

using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using EPiServer.DataAbstraction;
using EPiServer.Web.PropertyControls;
 
namespace EPiServer.Templates.Public.CustomProperty
{
    public class PropertyDropdownCheckListControl : PropertyTextBoxControlBase
    {
        protected System.Web.UI.WebControls.ListBox listBox;
 
        public override bool SupportsOnPageEdit
        {
            get { return false; }
        }
 
        public PropertyDropdownCheckList CategoryCheckBoxList
        {
            get { return PropertyData as PropertyDropdownCheckList; }
        }
 
        public override void CreateEditControls()
        {
            this.listBox = new ListBox();
            listBox.SelectionMode = ListSelectionMode.Multiple;
            listBox.ID = "DropdownCheckList";
 
            CategorySettings settings = (CategorySettings) base.PropertyData.GetSetting(typeof (CategorySettings));
 
            Category mainCategory = Category.Find(settings.RootCategory);
            var values = CategoryCheckBoxList.Value as string;
 
            foreach (Category c in mainCategory.Categories)
            {
                ListItem li = new ListItem(c.LocalizedDescription, c.Name);
 
                if (!string.IsNullOrEmpty(values))
                {
                    foreach (string value in values.Trim().Split('|'))
                    {
                        if (value == c.Name)
                        {
                            li.Selected = true;
                        }
                    }
                }
 
                listBox.Items.Add(li);
            }
 
            ApplyControlAttributes(listBox);
 
            Controls.Add(listBox);
 
            this.RegisterResources();
        }
 
        public override void ApplyEditChanges()
        {
            string values = string.Empty;
            foreach (ListItem listItem in this.listBox.Items)
            {
                if (listItem.Selected)
                {
                    values += listItem.Value + "|";
                }
            }
 
            SetValue(values);
        }
 
        private void RegisterResources()
        {
            Page.Header.Controls.Add(CreateCssLink("~/templates/public/customproperty/ui.dropdownchecklist.css", "screen"));
 
            if (!Page.ClientScript.IsClientScriptIncludeRegistered("jQuery"))
            {
                Page.ClientScript.RegisterClientScriptInclude("jQuery", "/templates/public/customproperty/jquery-min.js");
            }
 
            if (!Page.ClientScript.IsClientScriptIncludeRegistered("uicore"))
            {
                Page.ClientScript.RegisterClientScriptInclude("uicore", "/templates/public/customproperty/ui.core-min.js");
            }
 
            if (!Page.ClientScript.IsClientScriptIncludeRegistered("dropdownchecklist"))
            {
                Page.ClientScript.RegisterClientScriptInclude("dropdownchecklist", "/templates/public/customproperty/ui.dropdownchecklist-min.js");
            }
 
            Page.ClientScript.RegisterStartupScript(GetType(), "dropdownchecklist-setup" + this.GetHashCode(), string.Format("$('#{0}').dropdownchecklist();", listBox.ClientID), true);
        }
 
        public static HtmlLink CreateCssLink(string cssFilePath, string media)
        {
            var link = new HtmlLink();
            link.Attributes.Add("type", "text/css");
            link.Attributes.Add("rel", "stylesheet");
            link.Href = link.ResolveUrl(cssFilePath);
            if (string.IsNullOrEmpty(media))
            {
                media = "all";
            }
 
            link.Attributes.Add("media", media);
            return link;
        }
    }
}

And the result in edit mode:
Dropdown Check List in EPiServer edit mode

There are a ton of things you can do with the plugin to customize it even more. Check out the demo page for some more samples.

Download the code

EPiCode.Extensions and ambiguous reference

On new projects where I use EPiCode.Extensions I always register the namespace EPiCode.Extensions in my web.config – that way I can use the extension methods in my .aspx and .ascx files without needing to register EPiCode.Extensions in every file.

...
      <namespaces>
        ...
        <add namespace="EPiCode.Extensions" />     
      </namespaces>
    </pages>
...

Sometimes this can cause some problems when you have other extension methods with the same method signature.

Ambiguous call between two extension methods with the same signature

In this case it was with EPiServer Composer. To fix it I created a simple web.config file that I placed inside the Dropit\Plugin\Extension folder.

Here’s the code.

<?xml version="1.0"?>
<configuration>
  <system.web>
      <pages>
          <namespaces>
              <remove namespace="EPiCode.Extensions" />
          </namespaces>
      </pages>
  </system.web>
</configuration>

You can also use the location element of your main web.config file instead.

<location path="dropit">
        <system.web>
            <pages>
                <namespaces>
                    <remove namespace="EPiCode.Extensions" />
                </namespaces>
            </pages>
        </system.web>
    </location>

And that’s it! This will also work for all the sub directories as well.

On a side-note: I’ve been adding a lot of new extension methods lately to the project. I’ve listed them on the project’s wiki-page. Go check them out!

EPiServer Developer Resources

Last updated 05.07.2010

Table of Contents

  1. Report Center
  2. Mobile
  3. Bugs and where to find help
    1. FAQ
  4. Subscription
  5. Categories
  6. Import / Export
  7. Content Channels
  8. URL rewriting / friendly URL
  9. TinyMCE / Editor
  10. XForms
  11. Globalization / localization
  12. File system / VPP
  13. Security, Membership and roles
  14. Events
  15. Oracle
  16. SEO
  17. Workflows
  18. Errors, Logging and debugging
    1. Logging
    2. Errors and Error handling
    3. Debugging
  19. Configuration
  20. Getting started guides and tutorials
  21. Checklists
  22. SDK and API documentation
  23. Guides
  24. EPiServer Framework
    1. Online Center
      1. Gadgets
    2. Dynamic Data Store
      1. Page Objects
      2. Dynamic Data Store
    3. Initialization System
  25. Modules
    1. Modules and deployment center
    2. Open Source Modules
      1. Templates
      2. Gadgets
      3. Page Providers
      4. Virtual Page Providers
      5. Google Analytics and SEO
      6. Dynamic Content
      7. Images, Image galleries and slideshows
      8. Google Map
      9. Properties
      10. Language, Globalization and Localization
      11. Reports
      12. Debugging and diagnostics
      13. Frameworks
      14. Performance and caching
      15. RSS and feeds
      16. Edit mode enhancements
      17. Blog
      18. Various modules
      19. Enhancements for editors
      20. Rich Text Editor enhancements
    3. EPiServer Composer
    4. EPiServer Community
      1. Tech-notes
      2. More resources
    5. EPiServer Commerce
    6. EPiServer Relate+
    7. EPiServer Mail
    8. EPiServer CMO
    9. EPiServer Connect for CRM
    10. EPiServer Connect for SharePoint
  26. Extending EPiServer
    1. Plugins
    2. Custom Property
    3. Dynamic Content
    4. Scheduled Jobs
  27. EPiServer Enterprise
    1. Load Balancing
    2. Server Architecture
    3. EPiServer Enterprise
    4. Mirroring
    5. Page Providers
  28. Developing with EPiServer
    1. Web Controls
    2. Page Types and PageData
    3. Properties / Dynamic Properties
    4. Code architecture
    5. Searching and filtering
  29. Performance and caching
    1. Caching
    2. Performance
  30. EPiServer Quick Publishing

Report Center

EPiServer’s Report Center comes with 6 predefined reports.

  • Not Published Pages
  • Published Pages
  • Changed Pages
  • Expired Pages
  • Simple Addresses
  • Link Status

For a short guide to using the existing reports see the guide: EPiServer CMS R2: Report Center.

To get started developing your own reports see: Create Your Own Reports in the Report Center and PageName vs UrlSegment Report.

Mobile

Bugs and where to find help

Often the first thing I do when I’m stuck on a problem is to go to EPiServer’s bug list and do a quick search to see if by problem might be reported in as a bug. Next up after that is Google, if I cannot find an answer there I try to post a clear description of my problem on the forum or create a support ticket.

FAQ

Not sure if it’s still in use but EPiServer World’s FAQ still contains some valuable information.

Subscription

EPiServer Subscription is used for sending email updates to users when new content is published.

These articles should at least give you a little information about EPiServer’s subscription functionality. For some sample code see the Public Templates under Pages and SubscriptionPage.aspx.

Categories

Like with Subscription there is not much documentation and blog posts about EPiServer’s built in category functionality. I’ve started using categories more for tagging pages, which I then use to filter search pages and list pages.

Here are a few resources on categories.

Import / Export

EPiServer has built in functionality for importing and exporting pages, files, categories, page types, and more. This creates an .episerverdata file that you can open up with a program like WinRar and see its content, which consists of a bunch of xml files.

Content Channels

Content Channels are used for pushing external data into EPiServer. This is for instance used by the SharePoint connector for pushing data into EPiServer from SharePoint.

For a nice introduction see:  Pushing Data into EPiServer CMS 5 via Content Channels, there is also the video: Content Channel and Custom Page Store in EPiServer CMS 5.

URL rewriting / friendly URL

Both for users and search engines it helps to use friendly urls. Since EPiServer’s URL rewriter is provider based, it is easy to replace it with your own implementation.

Below are a couple of resources for changing the built in functionality of EPiServer’s URL rewriter. I recommend using Reflector to learn more about the inner workings of the URL rewriter (in EPiServer.dll and the EPiServer.Web namespace).

TinyMCE / Editor

With the rich text editor we want to add custom styles to the content and add new functionality and plugins, below are a couple of links that should help you with this.

The default editor for EPiServer CMS 6 is TinyMCE, if you upgrade from EPiServer CMS 5 or use EPiServer CMS 5, EPiServer’s built in editor is used. You can change which editor you wish to use in your web.config file, see: XHTML Editor – PropertyXHTMLString and PropertyLongString for more information.

XForms

EPiServer XForm is used for creating user forms. EPiServer uses an editor for letting the editors of the site build the forms. As developers we can easily extend and attach our self to various events that get triggered when the forms is sent (as an email, stored in the database or both).

A trick to note when using the XForm editor is that ctrl + shift + c and ctrl + shift + v copies/pastes the markup generated by the XForm editor, allowing you to easily change it without needing to attach yourself to various events and change the markup there.

For some sample code on rendering the XForm on your site see the Public Templates and XForm.ascx and the XForm page type.

Globalization / localization

EPiServer has some powerful globalization and localization support, built on ASP.NET’s globalization and localization functionality. I recommend starting out with the Globalization tech-note. EPiServer uses xml files to store the language information inside the lang folder. When installing a new EPiServer site there are quite a few default language files that get installed with it, I recommend deleting all the files you do not use.

Also be sure to check out Manage Languages for keeping language files up to date and TranslateX for sending EPiServer CMS pages to/from a translation service.

File system / VPP

EPiServer uses Microsoft’s Virtual Path Provider for their file system. Each file has a version history and supports meta data properties for storing information like author, copyright and other information, see my post:  EPiServer File Manager and File Summary for information on how to add more meta data properties.

There has also been developed a module for storing the files in the database instead of on a file share or on the web server.

Security, Membership and roles

EPiServer uses ASP.NET’s membership and role provider model for their membership and roles. By default these providers ship with EPiServer:

  • OracleMembershipProvider
  • WindowsMembershipProvider
  • SqlServerMembershipProvider
  • ActiveDirectoryMembershipProvider
  • MultiplexingMembershipProvider

MultiplexingMembershipProvider forwards requests to the Windows- and SqlServerMembershipProvider, allowing for creating and storing users and roles in EPiServer’s database and using the Windows users and roles (this is the mostly used provider).

Events

Oracle

EPiServer supports Oracle databases and even comes with sample configuration settings in their config files.

SEO

Here are a few blog posts and modules with tips on making EPiServer even more SEO friendly.

Workflows

EPiServer uses Windows Workflow Foundation for their Workflows and even ship with 4 workflows:

  • Sequential Approval
  • Parallel Approval
  • Request for feedback
  • Ready for translation

See Enabling the EPiServer CMS Workflows for information on how to activate them.

Errors, Logging and debugging

Logging

Errors and Error handling

Debugging

Configuration

EPiServer stores a lot of its configuration settings in various .config files. Below are a few resources that’ll help you navigate through most of what you can configure.

Overview of the default config files that come with EPiServer (containing both ASP.NET and EPiServer settings).

  • web.config – The main configuration file for the application. Contains configuration for the ASP.NET API and some parts of the EPiServer CMS API.
  • episerver.config – The main configuration file for the EPiServer CMS API. Contains the basic settings for the EPiServer CMS site (or sites – in an enterprise installation).
  • episerverFramework.config – Contains mapping information describing which host addresses leads to a particular EPiServer CMS site.
  • connectionStrings.config – Contains a list of database connection strings

There are two further configuration files located in the application’s root folder. These two configuration files are separate and not related to the files listed above or each other.

  • episerverLog.config – Contains the log4net settings for the application, please see the log4net homepage for full information on configuration options.
  • fileSummary.config – An XForm defining the meta data properties attached to files that are uploaded to EPiServer CMS.

Getting started guides and tutorials

Checklists

SDK and API documentation

Guides

EPiServer Framework

EPiServer Framework consists of:

  • EPiServer OnlineCenter
  • Dynamic Data Store
  • Initialization System

For a good introduction see: Introducing EPiServer Framework.

Online Center

Gadgets

Dynamic Data Store

The Dynamic Data Store is a new feature that came with EPiServer CMS 6 and is essentially a place to store data that might not be best stored in a page property. XForms for instance are stored in the Dynamic Data Store.

Page Objects

Page Objects are .Net objects and collections that are associated with an EPiServer CMS page.

Dynamic Data Store

There are two things you need to read to understand most of the Dynamic Data Store. First the tech-note: Dynamic Data Store, and second the examples referred to in the tech-note: Dynamic Data Store Examples.

More resources

Initialization System

Modules

This section contains how to create module packages for the deployment center, open source modules, and other EPiServer modules.

Modules and deployment center

The deployment center allows us to easily install new packages on existing sites. A package is a zip file with the necessary files that the modules needs along with configuration settings that need to be added to the various configuration files.

Open Source Modules

Most of the open source modules out there are hosted on either EPiCode or CodePlex. Here is a list of the various open source modules that I know about.

Templates

Gadgets

Page Providers

Virtual Page Providers

Google Analytics and SEO

Dynamic Content

Images, Image galleries and slideshows

Google Map

Properties

Language, Globalization and Localization

Reports

Debugging and diagnostics

Frameworks

Performance and caching

RSS and feeds

Edit mode enhancements

Blog

Various modules

Enhancements for editors

Rich Text Editor enhancements

EPiServer Composer

EPiServer’s Composer module is used to add extra functionality to EPiServer CMS pages, allowing editors to drag and drop functionality on predefined placeholders.

EPiServer Community

EPiServer Community is a framework for building online communities and consists of modules for user management, video galleries, chat, blogs etc.

The EPiServer Community SDK has a great howto section that covers a lot of the topics you as a developer will come across when working with EPiServer Community.

Joel Abrahamsson has also written a great series on creating new modules for EPiServer Community:

Tech-notes

More resources

EPiServer Commerce

Before trying to install EPiServer Commerce read the release notes and the section “Known Limitations”.

EPiServer Relate+

EPiServer Relate+ consists of a set of templates that builds on EPiServer Community and EPiServer CMS, and gets you started with a sample site.

EPiServer Mail

EPiServer Mail is used for sending emails and newsletters and is used by EPiServer Community and EPiServer Relate+.

EPiServer CMO

EPiServer CMO is used for monitoring and optimizing pages on your website by learning about your users’ behavior and helping your editors easily create A/B tests.

EPiServer Connect for CRM

EPiServer Connect for SharePoint

Extending EPiServer

One of EPiServer’s biggest strengths in my humble opinion is how easy EPiServer is to extend. Take a look at this picture by Deane Barker for a great overview of what is possible.

Plugins

Custom Property

Dynamic Content

Scheduled Jobs

EPiServer Enterprise

Load Balancing

Server Architecture

EPiServer Enterprise

Mirroring

Page Providers

Developing with EPiServer

Web Controls

Page Types and PageData

Properties / Dynamic Properties

Code architecture

Searching and filtering

Performance and caching

EPiServer has some great performance and caching out of the box (usually 90-95% of pages are served from the cache!). Below are some resources for improving it even more. For client side performance I recommend checking out YSlow as well.

Caching

Performance

EPiServer Quick Publishing

EPiServer Custom Property with Custom Settings

I was brushing up on custom properties and came across Allan Thræn’s post Custom Property: Category Drop Down. The code is simple and works great, but one thing I didn’t like is that you need to give the property the same name as the root category that you use to populate the drop down.

In EPiServer CMS 6 we now have the ability to add settings to the properties. Linus Ekström wrote a great post on how to use the new settings functionality: Settings for properties. After reading both Allan’s and Linus’ post I decided to give the EPiServer administrator the ability to choose which category should be the root category in the settings tab of the property.

Custom Property

using System;
using EPiServer.Core.PropertySettings;
using EPiServer.PlugIn;
 
namespace EPiServer.Templates.Properties
{
    [Serializable]
    [PageDefinitionTypePlugIn]
    [PropertySettings(typeof(CategoryDropDownSettings), true)]
    public class CategoryDropDown : EPiServer.Core.PropertyString
    {
 
        public override EPiServer.Core.IPropertyControl CreatePropertyControl()
        {
            return new CategoryDropDownControl();
        }
    }
}

The code is almost identical to Allan’s except for the PropertySettings attribute.

using System.Web.UI.WebControls;
using EPiServer.DataAbstraction;
 
namespace EPiServer.Templates.Properties
{
    public class CategoryDropDownControl : EPiServer.Web.PropertyControls.PropertyTextBoxControlBase
    {
 
        public override bool SupportsOnPageEdit
        {
            get
            {
                return false;
            }
        }
 
        protected DropDownList ddl;
 
        public override void CreateEditControls()
        {
            ddl = new DropDownList();
            CategoryDropDownSettings settings = (CategoryDropDownSettings)base.PropertyData.GetSetting(typeof(CategoryDropDownSettings));
 
            Category main_c = Category.Find(settings.RootCategory);
            ddl.Items.Add(new ListItem("", ""));
            foreach (Category c in main_c.Categories)
            {
                ListItem li = new ListItem(c.LocalizedDescription, c.Name);
                li.Selected = (((string)CategoryDropDown.Value) == c.Name);
                ddl.Items.Add(li);
            }
 
            this.ApplyControlAttributes(ddl);
            Controls.Add(ddl);
        }
 
        public override void ApplyEditChanges()
        {
            SetValue(ddl.SelectedValue);
        }
 
        public CategoryDropDown CategoryDropDown
        {
            get
            {
                return PropertyData as CategoryDropDown;
            }
        }
    }
}

Only difference to Allan’s code here is in the CreateEditControls method.

...
CategoryDropDownSettings settings = (CategoryDropDownSettings)base.PropertyData.GetSetting(typeof(CategoryDropDownSettings));
 
Category main_c = Category.Find(settings.RootCategory);
...

Custom Settings

using EPiServer.Core.PropertySettings;
 
namespace EPiServer.Templates.Properties
{
    [PropertySettingsUI(AdminControl = typeof(CategoryDropDownSettingsUI))]
    public class CategoryDropDownSettings : PropertySettingsBase
    {
        public int RootCategory { get; set; }
 
        public override IPropertySettings GetDefaultValues()
        {
            return new CategoryDropDownSettings { RootCategory = 0 };
        }
    }
}

I’m setting the default rootCategory to be 0 (root).

using System.Linq;
using System.Web.UI.WebControls;
using EPiServer.Core;
using EPiServer.Core.PropertySettings;
using EPiServer.Web.WebControls;
 
namespace EPiServer.Templates.Properties
{
    public class CategoryDropDownSettingsUI : PropertySettingsControlBase
    {
        private InputCategoryTree _categoryTree;
 
        protected override void CreateChildControls()
        {
 
            base.CreateChildControls();
 
            _categoryTree = new InputCategoryTree {ID = "CategoryTree"};
 
            Label label = new Label { Text = "Root Category", AssociatedControlID = "CategoryTree" };
 
            Controls.Add(label);
 
            Controls.Add(_categoryTree);
 
        }
 
        public override void LoadSettingsUI(IPropertySettings propertySettings)
        {
 
            EnsureChildControls();
 
            _categoryTree.SelectedCategories = new CategoryList(new[] {((CategoryDropDownSettings)propertySettings).RootCategory});
        }
 
        public override void UpdateSettings(IPropertySettings propertySettings)
        {
 
            EnsureChildControls();
 
            // We only want the first selected category
            ((CategoryDropDownSettings)propertySettings).RootCategory = int.Parse(_categoryTree.SelectedCategories.ElementAt(0).ToString());
        }
    }
}

When we add a new property we now have the option, under custom settings, to choose the root category for our drop down.

EPiServer Category Drop Down Settings

Which gives our editors these options.

EPiServer Category Drop Down in view mode

Creating a simple image gallery with EPiServer

If you have visited sites like Smashing Magazine chances are high that you’ve seen articles with titles like “40 most used jQuery plugins”, or something similar to that. I find articles like that to be great for inspiration. You usually have a section for galleries/slideshows/carousels etc, I thought I’d implement one of those plugins in EPiServer, just to show you have simple it is.

jQuery GalleryView

GalleryView is a jQuery plugin for displaying a gallery of images. The plugin is easy to use and setup, simply download the files and include them in your project.

jQuery GalleryView files in Visual Studio

Dynamic Content

We’re going to create a dynamic content plugin that our editors can use to add a gallery to a page. Start by creating a new class and give it the name Gallery.cs. Make sure it implements the IDynamicContent interface.

I’m using the custom property Folder Browser Property from EPiCode to let the editor choose a root folder for the images. I’ve also added a user control for displaying the result to the users of the site.

The complete class looks like this.

using EPiServer.Core;
using EPiServer.DynamicContent;
using Meridium.FolderBrowserProperty.Web.UI.PropertyControls;
 
namespace EPiServer.Templates.Public.Plugins
{
    public class Gallery : IDynamicContent
    {
        protected PropertyFolderBrowser MediaFolder; 
 
        public Gallery()
        {
            MediaFolder = new PropertyFolderBrowser {Name = "Media folder"};
        }
 
        public System.Web.UI.Control GetControl(PageBase hostPage)
        {
            var gallery = hostPage.LoadControl("~/Templates/Public/Units/Gallery.ascx") as Units.Gallery;
 
            if (gallery == null)
            {
                return null;
            }
 
            gallery.Root = this.State;
 
            return gallery;
        }
 
        public PropertyDataCollection Properties
        {
            get
            {
                return new PropertyDataCollection {MediaFolder};
            }
        }
 
        public string Render(PageBase hostPage)
        {
            return string.Empty;
        }
 
        public bool RendersWithControl
        {
            get { return true; }
        }
 
        public string State
        {
            get
            {
                return MediaFolder.ToString();
            }
            set
            {
                MediaFolder.ParseToSelf(value);
            }
        }
    }
}

After you register it in episerver.config (web.config for CMS 5), you’ll be able to choose it in your sites WYSIWYG-editor.

<dynamicContent>
    <controls>
      ...
      <add description="Gallery" name="Gallery" type="EPiServer.Templates.Public.Plugins.Gallery, EPiServer.Templates.Public" />
    </controls>
</dynamicContent>

Gallery Dynamic Content in EPiServer Edit Mode

Gallery View Mode

The user control that displays the actual gallery to the users of the site.

<%@ Control Language="C#" AutoEventWireup="false" CodeBehind="Gallery.ascx.cs" Inherits="EPiServer.Templates.Public.Units.Gallery" %>
<link href="/galleryview-2.1.1/galleryview.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script src="/galleryview-2.1.1/jquery.easing.1.3.js" type="text/javascript"></script>
<script src="/galleryview-2.1.1/jquery.timers-1.2.js" type="text/javascript"></script>
<script src="/galleryview-2.1.1/jquery.galleryview-2.1.1.js" type="text/javascript"></script>
 
<asp:Repeater runat="server" ID="rptGallery">
    <HeaderTemplate>
        <ul class="gallery">
    </HeaderTemplate>
    <ItemTemplate>
    <%# SetImage(Container.DataItem) %>
 
        <li><img src="<%# Image.VirtualPath %>" alt="<%# Image.Summary.Title %>" />
            <div class="panel-overlay">
				<h3><a href="<%= Image.Summary.Dictionary["Website"] %>"><%= Image.Summary.Author %></a></h3>
				<p><%# Image.Summary.Dictionary["Description"] %></p>
			</div>
        </li>
    </ItemTemplate>
    <FooterTemplate>
        </ul>
    </FooterTemplate>
</asp:Repeater>
 
<script type="text/javascript">
    $('.gallery').galleryView({
        panel_width: 800,
        panel_height: 300,
        frame_width: 100,
        frame_height: 100
    });
</script>
using System;
using EPiServer.Web.Hosting;
 
namespace EPiServer.Templates.Public.Units
{
    public partial class Gallery : UserControlBase
    {
        public string Root
        {
            get; set;
        }
 
        protected UnifiedFile Image
        {
            get; private set;
        }
 
        protected string SetImage(object dataItem)
        {
            this.Image = dataItem as UnifiedFile;
 
            return string.Empty;
        }
 
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
 
            if (string.IsNullOrEmpty(this.Root))
            {
                return;
            }
 
            var rootFolder = System.Web.Hosting.HostingEnvironment.VirtualPathProvider.GetDirectory(this.Root) as UnifiedDirectory;
 
            if (rootFolder == null)
            {
                return;
            }
 
            this.rptGallery.DataSource = rootFolder.Files;
            this.rptGallery.DataBind();
        }
    }
}

Result

The gallery in EPiServer View Mode

Note on Folder Browser Property

I’ve added an EPiServer CMS 6 version of Folder Browser Property to EPiCode.

Usage

  1. SVN Checkout https://www.coderesort.com/svn/epicode/Meridium.FolderBrowserProperty/6.x/ (requires registration on EPiCode)
  2. Open up the project in Visual Studio and build
  3. Copy Meridium.FolderBrowserProperty.dll to your sites bin folder (remember to add a reference in your Visual Studio project as well)
  4. Create the folders “<Site root>\Meridium\FolderBrowserProperty\Dialogs”, and copy the file FolderBrowserDialog.aspx into it

Hope this helps.

EPiServer File Manager and File Summary

One hidden little feature that is nice to know about is the filesummary.config file. When you edit a file in EPiServer’s File Manager, you can edit the data for that file (simply right-click on the file and choose Edit File Summary).

Edit File Summary in EPiServer Edit Mode

Which gives us this form.

Edit File Summary in EPiServer Edit Mode form

This is the standard form that comes with EPiServer.

FileSummary.config

We can easily change the form by editing FileSummary.config. If we open it in a source code editor, the code looks something like this.

<root xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <model>
    <instance>
      <Author />
      <DocumentType />
      <Category />
      <Publisher />
      <Description />
    </instance>
  </model>
  <table id="id_matrix" border="0">
    <tr>
      <td class="EP-tableCaptionCell">
        <label for="id_field2" id="id_field1" style="margin-bottom: 10px;">Author</label>
      </td>
      <td valign="top">
        <xforms:input ref="Author" value="" id="id_field2" size="40" class="episize240" />
      </td>
    </tr>
    <tr>
      <td class="EP-tableCaptionCell">
        <label for="id_field13" id="id_field6">Publisher</label>
      </td>
      <td valign="top">
        <xforms:input ref="Publisher" value="" id="id_field13" size="-1" class="episize240" />
      </td>
    </tr>
    <tr>
      <td class="EP-tableCaptionCell">
        <br />
        <label for="id_field12" id="id_field5">Type of document</label>
      </td>
      <td valign="top">
        <xforms:select1 appearance="full" ref="DocumentType" id="id_field12">
          <xforms:item>
            <xforms:label>Whitepaper</xforms:label>
            <xforms:value>Whitepaper</xforms:value>
          </xforms:item>
          <xforms:item>
            <xforms:label>Technote</xforms:label>
            <xforms:value>Technote</xforms:value>
          </xforms:item>
          <xforms:item>
            <xforms:label>Manual</xforms:label>
            <xforms:value>Manual</xforms:value>
          </xforms:item>
        </xforms:select1>
      </td>
    </tr>
    <tr>
      <td class="EP-tableCaptionCell">
        <br />
        <label for="id_field121" id="id_field5">Category</label>
      </td>
      <td valign="top">
        <xforms:select appearance="full" ref="Category" id="id_field121">
          <xforms:item>
            <xforms:label>Product1</xforms:label>
            <xforms:value>Product1</xforms:value>
          </xforms:item>
          <xforms:item>
            <xforms:label>Product2</xforms:label>
            <xforms:value>Product2</xforms:value>
          </xforms:item>
          <xforms:item>
            <xforms:label>Product3</xforms:label>
            <xforms:value>Product3</xforms:value>
          </xforms:item>
        </xforms:select>
      </td>
    </tr>
    <tr>
      <td class="EP-tableCaptionCell">
        <label for="id_field14">Description</label>
      </td>
      <td valign="top">
        <div id="id_field8">
          <xforms:textarea cols="37" rows="6" ref="Description" value="" id="id_field14" size="-1" />
        </div>
      </td>
    </tr>
  </table>
</root>

A combination of XML , HTML and XForm for storing the data. To add a new property we simply need to update the markup a little. Lets start by adding a new element inside model and instance.

<root xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <model>
    <instance>
      <Author />
      <Website />
      <DocumentType />
      <Category />
      <Publisher />
      <Description />
    </instance>
  </model>
...

Notice that I’ve added the <Website /> tag. We also need to insert a new row in the table with a XForm input element.

<tr>
  <td class="EP-tableCaptionCell">
	<label for="id_field31" id="id_field30" style="margin-bottom: 10px;">Website</label>
  </td>
  <td valign="top">
	<xforms:input ref="Website" value="" id="id_field31" size="40" class="episize240" />
  </td>
</tr>

If we save and go back to Edit Mode and the File Manager, the form should look something like this.

Edit File Summary in EPiServer Edit Mode update form with website field

For more information on XForm see: Developing with XForms.

Accessing the data

We can now access the property data by creating a new UnifiedFile instance of our file.

var file = System.Web.Hosting.HostingEnvironment.VirtualPathProvider.GetFile("/Global/Images/Portrait Employees/Robert.jpg") as UnifiedFile;

When we type file. in Visual Strudio, we see that we have access to a few public properties. The one we’re interested in is the Summary property.

The Summary property exposes a IUnifiedSummary type, which gives us access to properties like Author, Comments, Category etc, and more importantly a Dictionary for accessing other properties we create (like Website).

file.Summary.Dictionary["Website"]

Putting it all together

Here is a simple example that shows a picture with a caption.

<div class="featured">
	<img src="<%= Image.VirtualPath %>" alt="<%= Image.Summary.Title %>" />
	<p>
		<a href="<%= Image.Summary.Dictionary["Website"] %>"><%= Image.Summary.Author %></a>
		<em><%= Image.Summary.Dictionary["Description"]%></em>
	</p>
</div>
public UnifiedFile Image
{
	get; private set;
}
 
protected override void OnLoad(System.EventArgs e)
{
	base.OnLoad(e);
 
	this.Image = System.Web.Hosting.HostingEnvironment.VirtualPathProvider.GetFile("/Global/Images/Portrait Employees/Robert.jpg") as UnifiedFile;
}

A little CSS for making it look pretty.

.featured p
{
	background-color: rgba(0,0,0,.7);
	display: block;
	position: absolute;
	width: 100%;
	bottom: 0;
	left: 0;
	font-family: Georgia, serif;
	font-size: 1em;
	font-weight: normal;
	line-height: 1.3em;
	color: #ccc;
	margin-bottom: 0;
}
.featured
{
	width: 40%;
	overflow: hidden;
	position: relative;
}
 
.featured p a
{
	display: block;
	padding: 2px 10px 0 10px;
	font-weight: normal;
	font-style: italic;
	color: #fff;
}
.featured p em
{
	display: block;
	padding: 0 10px 2px 10px;
	font-style: normal;
	color: #e3c887;
}

And here’s the result!

Result with CSS

Updated all EPiServer posts for EPiServer CMS 6

I’ve done a little spring cleaning, updating all EPiServer posts to now use EPiServer CMS 6, and making sure the code still works. I’ve also added the code for ShareIt and SlideShare Dynamic Content to EPiCode, and updated EPiCode.Extensions. They’re all now built against EPiServer CMS 6.

My current projects on EPiCode

The Create an EPiServer site from scratch series is also updated for EPiServer CMS 6.

If you find any errors or broken links, please post a comment, or email me directly: frederikvig@hotmail.com. Thanks!

Adding different CSS classes when using the EPiServer PageTree control

Another little quick tip. I was browsing the EPiServer World forum and came across a common question.

by David Green

I am using the EpiServer:PageTree control to generate a nested <ul><li> list in the format below.

However I am also using a dropdown menu system called UDM which requires that the class and id “udm” are on the first <ul> tag.

The container object of the PageTree controller exposes the Indent property that we can use for this. Below is a simple example of how to add a CSS class to the first ul in your list (code is based on SubMenu.ascx from the EPiServer Public Templates package).

<%@ Control Language="C#" EnableViewState="false" AutoEventWireup="False" CodeBehind="SubMenu.ascx.cs" Inherits="EPiServer.Templates.Public.Units.Static.SubMenu" %>
<EPiServer:PageTree ShowRootPage="false" runat="server" id="Menu">
    <IndentTemplate>
        <ul <%# AddCssClassToFirstLevel(Container.Indent, "udm") %>>
    </IndentTemplate>
    <ItemHeaderTemplate>
        <li>
    </ItemHeaderTemplate>
    <ItemTemplate>
        <EPiServer:Property PropertyName="PageLink" runat="server" />
    </ItemTemplate>
    <SelectedItemTemplate>
	<EPiServer:Property CssClass="selected" PropertyName="PageName" runat="server" />
    </SelectedItemTemplate>
    <ItemFooterTemplate>
        </li>
    </ItemFooterTemplate>
    <UnindentTemplate>
        </ul>
    </UnindentTemplate>
</EPiServer:PageTree>
using System;
using EPiServer;
using EPiServer.Web.WebControls;
 
namespace EPiServer.Templates.Public.Units.Static
{
    public partial class SubMenu : UserControlBase
    {
        private MenuList _menuList;
 
        /// <summary>
        /// Gets or sets the data source for this control
        /// </summary>
        public MenuList MenuList
        {
            get { return _menuList; }
            set { _menuList = value; }
        }
 
        protected override void OnLoad(System.EventArgs e)
        {
            base.OnLoad(e);
 
            if (MenuList == null)
            {
                return;
            }
            Menu.PageLink = MenuList.OpenTopPage;
            Menu.DataBind();
        }
 
        protected string AddCssClassToFirstLevel(int level, string cssClassName)
        {
            if (level == 1)
            {
                return string.Format("class=\"{0}\"", cssClassName);
            }
 
            return string.Empty;
        }
    }
}

We can easily add more complex logic. We also have access to the HasChildren property, which tells us if the active page has any children.

Hope this helps.

Getting the Page and EPiServer CurrentPage object from HttpContext

Just a little quick tip when needing to use either the Page object or the EPiServer CurrentPage object from a class file. HttpContext.Current will give you access to the current request, what we can do is cast HttpContext.Current.Handler (since Page implements the IHttpHandler interface) to System.Web.UI.Page.

var page = HttpContext.Current.Handler as System.Web.UI.Page;
 
if (page != null)
{
    // do something with the page object
}

We can take this a step further and cast it to EPiServer.PageBase which gives us access to the CurrentPage object.

private static PageData CurrentPage
{
    get
    {
	var page = HttpContext.Current.Handler as EPiServer.PageBase;
 
	if (page == null)
	{
	    return null;
	}
 
	return page.CurrentPage;
    }
}

Visual Studio 2010 EPiServer Snippets

I finally got my hands on a copy of Visual Studio 2010 RC1! After playing around a bit, I stumbled across the new snippet functionality in Visual Studio 2010. You can now use snippets in the markup files as well (in previous versions you could only use the snippet functionality in code files like class/interfaces/code-behind files etc). This is very cool, and Microsoft has even included a few snippets for their ASP.NET controls and for HTML elements like: a, table, img, div etc. Quite a time saver!

To test the snippets out, simply type the shortcut (eg. ‘a’ or ‘table’) and press tab.

Visual Studio 2010 table snippet

Visual Studio 2010 table snippet

This is a simple, but very cool feature. Imaging all the typing you can get rid off!

Creating your own snippets

In Visual Studio 2010, under the Tools menu, you’ll find the Code Snippets Manager (ctrl+k, ctrl+b).

Visual Studio 2010 Code Snippets Manager

Here you can add new folders that contain your custom snippets, or check out the other snippets added by Microsoft. You’ll also see the path to the snippets folder (C:\Program Files (x86)\Microsoft Visual Studio 10.0\Web\Snippets\HTML\1033\ in my case). If you open up that folder in Windows Explorer you should see at least two folders there, ASP.NET and HTML. Inside both of these folders you’ll find the snippets for the ASP.NET web controls and for HTML elements. We can open up one of the files and take a look at the code.

<CodeSnippet Format="1.1.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <Header>
    <Title>image</Title>
    <Author>Microsoft Corporation</Author>
    <Shortcut>image</Shortcut>
    <AlternativeShortcuts>
      <Shortcut>imagebutton</Shortcut>
      <Shortcut Value="image">asp:image</Shortcut>
      <Shortcut Value="imagebutton">asp:imagebutton</Shortcut>
    </AlternativeShortcuts>
    <Description>Markup snippet for a control that contains an image</Description>
    <SnippetTypes>
      <SnippetType>Expansion</SnippetType>
    </SnippetTypes>
  </Header>
  <Snippet>
    <Declarations>
      <Literal>
        <ID>imageurl</ID>
        <ToolTip>imageurl</ToolTip>
        <Default>imageurl</Default>
      </Literal>
    </Declarations>
    <Code Language="html"><![CDATA[<asp:$shortcut$ imageurl="$imageurl$" runat="server" />$end$]]></Code>
  </Snippet>
</CodeSnippet>

Very easy and readable XML markup, that we easily can tweak to our needs. Say we’re working on a project where 90% of the tables we create should have a class of “products”. Lets create a snippet for this, so that we don’t have to type the same thing every time.

Create a new snippet called table-products.snippet, open it up in your favorite code editor and add this code.

<CodeSnippet Format="1.1.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <Header>
    <Title>table</Title>
    <Author>Frederik Vig</Author>
    <Shortcut>tablep</Shortcut>
    <Description>Markup snippet for a table with class products</Description>
    <SnippetTypes>
      <SnippetType>Expansion</SnippetType>
      <SnippetType>SurroundsWith</SnippetType>
    </SnippetTypes>
  </Header>
  <Snippet>
    <Declarations>
      <Literal>
        <ID>cellspacing</ID>
        <ToolTip>cellspacing</ToolTip>
        <Default>0</Default>
      </Literal>
    </Declarations>
    <Code Language="html"><![CDATA[<table cellspacing="$cellspacing$" class="products">
    <tr>
        <td>$selected$$end$</td>
    </tr>
</table>]]></Code>
  </Snippet>
</CodeSnippet>

I’ve saved table-products.snippet directly in the HTML snippet folder (C:\Program Files (x86)\Microsoft Visual Studio 10.0\Web\Snippets\HTML\1033\HTML in my case), but you can save it anywhere, just remember to add the snippet folder with the Code Snippets Manager in Visual Studio.

We can now test the snippet by typing tablep and pressing tab.

Visual Studio 2010 table products snippet

Visual Studio 2010 table products snippet

Simple example, I know, but you get the idea!.

EPiServer

Naturally, one of the first things I did was add the EPiServer Property web control to the snippet manager ;) . This turned out to be very easy! So I continued on adding snippets for the other EPiServer web controls as well. Here is the list of snippets with their shortcut.

Download the snippets

© Copyright Frederik Vig. Based on Fluid Blue theme