Building the Thumbnail Button Module

Posted Tuesday, September 13, 2011 7:04 PM by Kevin

When I set out to create an easier way to set thumbnails in Sitecore, I had a picture in my mind of how I wanted it to work, but I didn’t really know where to start!  I hadn’t built a custom ribbon button before.  I hadn’t created a modal dialog before nor did I know how to display an existing one.  And I had no idea how to receive results from one even if I could display it.  I had a lot of digging to do, so I fired up Google and .NET Reflector and got to work.

The first step was figuring out how to put a button where I wanted it in the ribbon with the text and icon I wanted to display.  Google gave me a few blog posts discussing this, but I never found exactly the info I was looking for.  I ended up just playing with it until I got it to work, but in the process this is what I figured out:

  • The ribbon is made of tabs or “strips”.  These appear across the top of Content Editor windows and I’m sure you’re familiar with them…  “Home”, “Navigate”, “Review”, “Analyze”, “Publish”, etc.  There is a template used to create these – /sitecore/templates/System/Ribbon/Strip.
  • These strips are then broken into “chunks”.  These are the boxes that group the buttons in the ribbon.  For example, in Content Editor’s “Home” strip, you would see these chunks:  “Edit”, “Insert”, “Operations”, “Clipboard”, “Rename”, and “Sorting”.  The template used to create chunks is /sitecore/templates/System/Ribbon/Chunk.
  • Lastly, within chunks there are buttons.  And there are different types of buttons – small buttons, large buttons, buttons that make a drop-down appear...  I used a large button (template is /sitecore/templates/System/Ribbon/Large Button) for my thumbnail button, but it looks like there are a lot of interesting possibilities here.
  • If you want to add your own strips, chunks, and/or buttons to the ribbon, open up the Core database and drill down to /Applications/Content Editor/Ribbons.  Note these are built to be re-usable, so there is a folder for strips and a folder for chunks – the Default ribbon has children using the Reference template (/sitecore/templates/System/Reference) pointing to the actual strips (so the same strip can be pointed to multiple times) and each strip’s children also use references pointing to its chunks (so the same chunk can appear in multiple strips).  It doesn’t appear that Sitecore is using references for buttons and I didn’t try it, but it may be possible to place buttons into multiple chunks that way as well.

So to get into specifics, I wanted to add a Thumbnail button to the Appearance chunk on the Configure strip (this is where Sitecore placed their “Icon” button, so it seemed like a good fit).  So in the Core database, I drilled down to /Applications/Content Editor/Ribbons/Chunks/Appearance and added a new Large Button using the /sitecore/templates/System/Ribbon/Large Button template.  Here’s a screenshot:

ThumbnailFields

I think the fields in this screenshot should be self-explanatory except for maybe “Click”.  This is the event you want raised when your button is clicked.  If you’re not familiar with these events, take a look at App_Config\Commands.config in one of your Sitecore solutions – it lists a ton of Sitecore’s internal events and the classes that handle them.

After adding the above, my button was already appearing in the ribbon - it just didn’t do anything when I clicked it.  If you looked at the Commands.config file, the next step may be clear...  I needed to wire my event (“example:Thumbnail” in the screenshot) to a class.  I took a look at some of the classes in Commands.config using .NET Reflector and discovered they all implement the Sitecore.Shell.Framework.Commands.Command abstract base class.

So, I created my own class that inherits Command and implemented the Execute() method.  I then created the following config include file and placed it in App_Config\Include\

 <configuration xmlns:patch= "http://www.sitecore.net/xmlconfig/ " 
                xmlns:x= "http://www.sitecore.net/xmlconfig/ ">
   <sitecore>
     <commands>
       <command name= "example:Thumbnail " type= "Example.Namespace.Class,Example.Assembly " />
     </commands>
   </sitecore>
 </configuration>
 

After doing this, I was able to place a breakpoint in my Execute() method and see that it was indeed being hit when I clicked the button.  Success!  But, what should my code inside of Execute() look like?  This is the point where I had to do a LOT of digging on Google and using Reflector.  I knew I wanted to display Sitecore’s media browser, but the question was HOW?

I won’t bore you with the entire process I went through (I don’t remember half of the things I tried anyway).  This is the key bit of code, though:

 UrlString  url = new  UrlString (UIUtil .GetUri("control:Sitecore.Shell.Applications.Media.MediaBrowser" ));
 Item  folderItem = masterDb.GetItem("/sitecore/media library/Images" );
 url["ro" ] = folderItem.Uri.ToString();
 SheerResponse.ShowModalDialog(url.ToString(), true );

As far as I can tell, "control:Sitecore.Shell.Applications.Media.MediaBrowser” is Sitecore’s “magic string” identifying the media browser dialog.  This code builds a URL pointing to the dialog with a querystring parameter identifying the root item for the browser (in this case, /sitecore/media library/Images), and then shows the dialog.

Initially, I placed this code in my class’ Execute() method.  After re-compiling, I was able to click the button and see the media browser, choose an image, and click OK.  But then nothing happened...  No way to capture what image was selected and save it to the database!

After lots and lots more exploring and experimenting, I found that I needed to start a client pipeline before showing the dialog and then wait for a postback in order to capture its result.  Here’s the minimal code to start the pipeline:

  NameValueCollection  parameters = new  NameValueCollection ();
  Context.ClientPage.Start(this , "Run" , parameters);
 

This basically tells Sitecore to start a pipeline and execute the “Run” method in the current class.  So I moved the ShowModalDialog() code into a new Run() method in my class.  The method gets passed a ClientPipelineArgs object, so the method signature looks something like this:

 protected  void  Run(ClientPipelineArgs  args)
 {
 }
 

Calling WaitForPostBack(true) on the args parameter after showing the dialog causes the pipeline to call my method again when a postback occurs (like, when the media browser dialog is closed).  When that happens, args.IsPostBack will be true AND args.Result will contain the dialog’s result.  So the Run() method skeleton looks like this:

 protected  void  Run(ClientPipelineArgs  args)
 {
     Database  masterDb = Factory .GetDatabase("master" );
 
     if  (args.IsPostBack)
     {
         // Do something with args.Result here.
      }
     else
      {
         // If this is not a postback, we want to display's media browser dialog.
          UrlString  url = new  UrlString (UIUtil .GetUri("control:Sitecore.Shell.Applications.Media.MediaBrowser" ));
 
         // We want the browser to be rooted in the Images folder in the media library.
          Item  folderItem = masterDb.GetItem("/sitecore/media library/Images" );
         url["ro" ] = folderItem.Uri.ToString();
 
         // These two lines displays the dialog and causes a postback to this method when it is closed.
          SheerResponse .ShowModalDialog(url.ToString(), true );
         args.WaitForPostBack(true );
     }
 }
 

One last thing I want to cover.  I wanted to limit when my button would appear (it doesn’t make sense to set a Thumbnail for items other than renderings and templates, I don’t think).  Luckily, this is pretty easy.  In your Command class, you can override the QueryState() method and have it return a CommandState telling Sitecore if your button should be enabled, disabled, or hidden.  It receives a CommandContext object that can be used to find out what the current item is in the Content Editor.

I’ll take this opportunity to once again link my full Thumbnail Button Module ThumbnailButtonModule-1.zip which contains the full source.  In addition to what I’ve covered here, it contains the QueryState() code, the code to update the Thumbnail field on the current item, and some code that passes the existing thumbnail in to the media browser so that it’s pre-selected when the dialog opens.

Being able to display Sitecore’s media browser dialog to allow a user to choose or upload an image will come in handy for other projects, so I’m really glad I put the effort into figuring out how to make it work.  Hopefully, I’ve been able to share this knowledge here and other people will be able to take advantage of it as well!  If you have any questions, comments, critiques, etc – please post a comment here on the blog or reach out to me via Twitter – @williamsk000.

Filed under:

Comments

# Open sitecore media library programmatically from asp.net button click | FaceColony.org - Developers Network

Pingback from  Open sitecore media library programmatically from asp.net button click | FaceColony.org - Developers Network

# Open sitecore media library programmatically from asp.net button click | PHP Developer Resource

Pingback from  Open sitecore media library programmatically from asp.net button click | PHP Developer Resource