Try our conversational search powered by Generative AI!

Linus Ekström
Feb 18, 2013
  7796
(5 votes)

Modifying the EPiServer UI views

Last Friday I saw a request on the forums if it was possible to change the order of the media and the shared blocks components so that the media component would be the one shown by default. I responded that I did not know a god way but since there seems to be several people wanting this I did a quick investigation if there was a decent ways to do this. I had three ideas to investigate:

  1. Hook up to the initialization and change the sort order of the file manager component definition.
  2. Replace the media component by registering a replacement component in the IOC container.
  3. Create an IViewTransformer that would resort the file manager component.

How a view is defined and set up

When a view is created for the EPiServer UI, there are several steps and extension points. Basically the view itself defines the main structure of the view and the possible plug-in areas. If we look at the home view of CMS it looks something like this:

  • Root
    • Navigation Pane [pluggable]
      • Default Navigation Group [pluggable]
    • Main Area
    • Assets Pane [pluggable]
      • Default Assets Group [pluggable]

And after the view system has been created and components have been plugged in a default installation will look something like this:

  • Root
    • Navigation Pane [pluggable]
      • Default Navigation Group [pluggable]
        • Pages
        • Sites
        • Tasks
    • Main Area
    • Assets Pane [pluggable]
      • Default Assets Group [pluggable]
        • Shared Blocks
        • File Manager

Components and Component Definitions

For each view that is created there will be a recursive look through to see if there are components that should be plugged into the view. When components are created there are two entities that you should be aware of:

  1. Component Definition – Responsible for defining where components should be plugged in, managing access rights and creating the actual component. This will normally use the singleton pattern.
  2. Component – The actual component that is created each time a view is loaded.

As a partner developer, you would usually only care about the ComponentDefinition and not the actual components created since this is mostly a bearer of data for the current view.

If you want to know more how the view is set up I suggest reading the following SDK article: http://sdkbeta.episerver.com/SDK-html-Container/?path=/SdkDocuments/EPiServerFramework/7/Knowledge%20Base/Developer%20Guide/User%20Interface/View%20Composition/View%20Composition.htm&vppRoot=/SdkDocuments//EPiServerFramework/7/Knowledge%20Base/Developer%20Guide/

Changing the sort order for the File Manager component definition

The first idea I had was to get hold of the singleton instance of the File Manager Component Definition in an initialization module and just change the sort order of the instance. The code I tried looks like this:

public void Initialize(Framework.Initialization.InitializationEngine context)
        {
            var componentManager = ServiceLocator.Current.GetInstance<IComponentManager>();
            var mediaComponentDefinition = componentManager.GetComponentDefinition("EPiServer.Cms.Shell.UI.Components.MediaComponent") as ComponentDefinitionBase;
 
            if(fileManagerComponentDefinition != null)
            {
                fileManagerComponentDefinition.SortOrder = 90;
            }
        }

Note: I’m using "EPiServer.Cms.Shell.UI.Components.MediaComponent" instead of typeof(MediaComponent).FullName to not have to take a dependency on the CMS UI add-on. This is not needed in EPiServer 7.6 and above since it's been moved to the bin folder.

Unfortunately the code above does not compile since SortOrder has a protected setter Ledsen so we have to move to the next potential solution.

Replace the file manager component

The next idea I had was to replace the media component by registering a custom component in the IOC container (http://sdkbeta.episerver.com/SDK-html-Container/?path=/SdkDocuments/EPiServerFramework/7/Knowledge%20Base/Developer%20Guide/User%20Interface/View%20Composition/How%20To/Replace%20a%20component%20globally.htm&vppRoot=/SdkDocuments//EPiServerFramework/7/Knowledge%20Base/Developer%20Guide/).

The idea is that whenever a component should be created, it’s possible to let the IOC container create an instance of custom type registered in the container. The code to do this would look something like this:

[InitializableModule]
    [ModuleDependency(typeof(Web.InitializationModule))]
    public class ClassFactoryInitialization : IInitializableModule
    {
        public void Initialize(Framework.Initialization.InitializationEngine context)
        {
            context.Container.Configure(ce =>
            {
                ce.For<IComponent>().Add<MovedFileManagementComponent>().Named("EPiServer.Cms.Shell.UI.Components.MediaComponent");
            });
        }
    }
 
    public class MovedMediaComponent : ComponentBase
    {
        public MovedMediaComponent()
            : base("epi-cms.component.FileManagement")
        {
            //Define all settings to mock the "real" media component.
        }
    }

 

Though doable I noticed that I have to create my custom component without any reference to the original component definition. This would simply cause too much copy and paste of settings to make a copy of the standard media component and with the risc of breaking when upgrading EPiServer. So I decided to move on to the third option…

Registering an IViewTransformer to move the Media Component

Last idea I had was to register an IViewTransformer. An IViewTransformer can be used to modify the view and there are actually quite a few used in the system:

  • Configuration view transformer – Makes it possible to modify some parts of the view through configuration.
  • Personalization view transformer – Enables user customizable parts of the view (add/remove/sort gadgets)
  • Sort component transformer – Sorts the actual components according to their given sort order. This makes it possible to plug-in a component at a specific place in the UI.

The idea here is to modify the sort order of the file manager component before the sort component transformer does the actual sorting. The code looks as follows:

using System;
using EPiServer.Shell.ViewComposition;
 
namespace Samples
{
    /// <summary>
    /// Moves the media component before the blocks component when creating a view.
    /// </summary>
    [ViewTransformer]
    public class SortComponentTransformer : IViewTransformer
    {
        /// <summary>
        /// Used to select the order of execution when there are several <see cref="IViewTransformer"/>s.
        /// </summary>
        public int SortOrder { get { return 7900; } }//Note: Default sort transformer has 8000
 
        /// <summary>
        /// Transforms the view according to the rules for the transformer.
        /// </summary>
        /// <param name="view">The view.</param>
        /// <param name="principal">The principal.</param>
        public void TransformView(ICompositeView view, System.Security.Principal.IPrincipal principal)
        {
            if (!String.Equals(view.Name, "/episerver/cms/home", StringComparison.OrdinalIgnoreCase))
            {
                //Only apply sorting for the cms home view.
                return;
            }
            SortContainerRecursively(view.RootContainer);
        }
 
        private void SortContainerRecursively(IContainer parentContainer)
        {
            foreach (IComponent component in parentContainer.Components)
            {
                IContainer childContainer = component as IContainer;
 
                if (childContainer != null)
                {
                    SortContainerRecursively(childContainer);
                }
                else if (String.Equals(component.DefinitionName, "EPiServer.Cms.Shell.UI.Components.MediaComponent", StringComparison.OrdinalIgnoreCase))
                {
                    //Change the sort order for the media component so that it's placed before the
                    //shared blocks component. Since this is done before sorting the components it will affect sorting.
                    component.SortOrder = 90;
                    return;
                }
            }
        }
    }
}

Actually, on this third attempt we have a working solution.

ResortedFileManager

There is one small caveat though that you should know about:

If the user has already personalized the Assets Pane, the sorting will be overridden by the personalization since this is applied after the sorting. This shouldn’t be a real problem as long as you implement the sorting before the users start using the system. If you add this on a system in use you might want to clear your views as described here: http://world.episerver.com/Blogs/Linus-Ekstrom/Dates/2013/1/Resetting-your-EPiServer-views/

Feb 18, 2013

Comments

Alexander Wagner
Alexander Wagner Feb 18, 2013 04:53 PM

Brilliant! Thank you very much!

Arild Henrichsen
Arild Henrichsen Feb 18, 2013 09:20 PM

Thanks for the quick response Linus! Excellent walkthrough of the alternatives.

Henning Sjørbotten
Henning Sjørbotten Sep 9, 2014 10:35 AM

Just what I needed, works great!

Yagnik Jadav (MVP)
Yagnik Jadav (MVP) Oct 18, 2017 08:08 AM

Hi Linus,

I read your couple of blog about custom component and content provider.

I am using latest version of CMS and trying to plug component with content provider at top of asset pane next to media and blocks tab but even I set DefaultAssetGroup, my component adding at bottom of asset pane.

Any idea?

Oct 19, 2017 12:24 PM

Hi Yagnik!

I am actually just about to resurect a project that I worked on over two years ago that has some parts implementing custom content and views. I will blog about this shortly, but for now: please have a look at the code in the Github repo to see if it helps you: https://github.com/LinusEkstrom/EpiserverExtensions.Settings

Please login to comment.
Latest blogs
Azure AI Language – Abstractive Summarisation in Optimizely CMS

In this article, I show how the abstraction summarisation feature provided by the Azure AI Language platform, can be used within Optimizely CMS to...

Anil Patel | Apr 18, 2024 | Syndicated blog

Fix your Search & Navigation (Find) indexing job, please

Once upon a time, a colleague asked me to look into a customer database with weird spikes in database log usage. (You might start to wonder why I a...

Quan Mai | Apr 17, 2024 | Syndicated blog

The A/A Test: What You Need to Know

Sure, we all know what an A/B test can do. But what is an A/A test? How is it different? With an A/B test, we know that we can take a webpage (our...

Lindsey Rogers | Apr 15, 2024

.Net Core Timezone ID's Windows vs Linux

Hey all, First post here and I would like to talk about Timezone ID's and How Windows and Linux systems use different IDs. We currently run a .NET...

sheider | Apr 15, 2024

What's new in Language Manager 5.3.0

In Language Manager (LM) version 5.2.0, we added an option in appsettings.json called TranslateOrCopyContentAreaChildrenBlockForTypes . It does...

Quoc Anh Nguyen | Apr 15, 2024

Optimizely Search & Navigation: Boosting in Unified Search

In the Optimizely Search & Navigation admin view, administrators can set a certain weight of different properties (title, content, summary, or...

Tung Tran | Apr 15, 2024