Posted in: Comments

First of all, this is not a new concept but the API has changed since EPiServer 7.14. IUIDescriptorInitializer is now obsolete. So here’s my take on this.

First we need an interface to “mark” the content types with:

namespace DV
{
    /// <summary>
    /// Interface to mark content types as container pages, i.e. changing the icon
    /// in the page tree and defaulting to All Properties view.
    /// </summary>
    public interface IContainerPage
    {
    }
}

Then we need a function to get all types that is marked with this interface, this is a straight copy of Valdis code but I wanted to include it in my post as well to avoid a possible dead link in the future:

namespace DV
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;

    /// <summary>
    /// Helper functions for working with types.
    /// </summary>
    public static class TypeFunctions
    {
        /// <summary>
        /// Get all types that implements or is a subclass of the specified type.
        /// </summary>
        /// <typeparam name="T">The type of the superclass.</typeparam>
        /// <returns>Returns a list of types that implements or is a subclass of the specified type.</returns>
        public static IEnumerable<Type> GetTypesChildOf<T>()
        {
            var types = new List<Type>();

            foreach (var assembly in TypeFunctions.GetAssemblies())
            {
                types.AddRange(TypeFunctions.GetTypesChildOfInAssembly(typeof(T), assembly));
            }

            return types;
        }

        private static IEnumerable<Assembly> GetAssemblies()
        {
            return AppDomain.CurrentDomain.GetAssemblies();
        }

        private static IEnumerable<Type> GetTypesChildOfInAssembly(Type type, Assembly assembly)
        {
            try
            {
                return assembly.GetTypes().Where(t => type.IsAssignableFrom(t) && t.IsClass);
            }
            catch (Exception)
            {
                // there could be situations when type could not be loaded
                // this may happen if we are visiting *all* loaded assemblies in application domain
                return Enumerable.Empty<Type>();
            }
        }
    }
}

Then we only need an initializable module that iterates through all UI descriptors, finds the ones that are marked with the IContainerPage interface and then finally set the default view and icon class.

namespace DV
{
    using System;
    using System.Linq;
    using EPiServer.Framework;
    using EPiServer.Framework.Initialization;
    using EPiServer.Shell;
    using EPiServer.ServiceLocation;

    [InitializableModule]
    [ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
    public class ContainerPageUIDescriptorInitialization : IInitializableModule
    {
        public void Initialize(InitializationEngine context)
        {
            var containerTypes = TypeFunctions.GetTypesChildOf<IContainerPage>();
            var registry = ServiceLocator.Current.GetInstance<UIDescriptorRegistry>();
            var containerDescriptors = registry.UIDescriptors.Where(d => containerTypes.Contains(d.ForType));

            foreach (var descriptor in containerDescriptors)
            {
                descriptor.DefaultView = CmsViewNames.AllPropertiesView;
                descriptor.IconClass = ContentTypeCssClassNames.Container;
            }
        }

        public void Preload(string[] parameters) { }

        public void Uninitialize(InitializationEngine context)
        {
            // Do nothing.
        }
    }
}