24 Sep 2010

Develop a custom editable Visual Web Part (WebPart) for SharePoint 2010

I wanted to create a web part for Sharepoint 2010 that would let an editor add a block of free-form html to a page, but wrapped up in a nicely formatted HTML container of my choosing. I also wanted the web part to include some custom properties to allow the user to select some permutations for the HTML container (colour, position etc.). The key thing was that when the editor is amending the content, I wanted to be able to use the standard ribbon controls instead of having to hook in a 3rd party rich text control like Telerik RadEditor.

So, I assumed I could just take the build-in Content Editor Web Part (CEWP) and extend it. No dice - cos it's sealed!

So I ended up whipping out Reflector and digging into the CEWP code, ripping the guts out of it to hack a new webpart. The following Web Part does what I set out to do, and maybe it will be a good base for you too.

Step 1: Create a new Visual Web Part called DCContentBlock.

Step 2: In the ASCX template, paste this:
<div class="DCContentBlock">
 <div class="DCContent">
  <asp:Panel ID="plhContentEdit" runat="server" />
  <asp:Panel ID="plhContentDisplay" runat="server" />
  <asp:Panel ID="plhNoContent" runat="server" />

Step 3: In the UserControl class in the ASCX.CS file, paste this:
  public Panel BodyContentEdit { get { return plhContentEdit; } }
  public Panel BodyContentDisplay { get { return plhContentDisplay; } }
  public Panel BodyNoContent { get { return plhNoContent; } }

Step 4: In the web part CS file, here is the main code to make this sucker work:
 public class DCContentBlock : Microsoft.SharePoint.WebPartPages.WebPart
  // Visual Studio might automatically update this path when you change the Visual Web Part project item.
  private const string _ascxPath = @"~/_CONTROLTEMPLATES/YOUR_PROJECT_NAME_HERE/DCContentBlock/DCContentBlockUserControl.ascx";

  private string _content;
  private DCContentBlockUserControl control;

  private HtmlGenericControl editableRegion = new HtmlGenericControl();
  private HtmlGenericControl emptyPanel = new HtmlGenericControl();

  private bool IsInEditMode
    SPWebPartManager currentWebPartManager = (SPWebPartManager)WebPartManager.GetCurrentWebPartManager(this.Page);
    return (((currentWebPartManager != null) && !base.IsStandalone) && currentWebPartManager.GetDisplayMode().AllowPageDesign);

  protected override void OnInit(EventArgs e)
   if (this.IsInEditMode)
    SPRibbon current = SPRibbon.GetCurrent(this.Page);
    if (current != null)
     if (!(this.Page is WikiEditPage))

  protected override void OnLoad(EventArgs e)

   // Prevent default display of webpart chrome in standard view mode
   this.ChromeType = PartChromeType.None;

   control = (DCContentBlockUserControl)Page.LoadControl(_ascxPath);
   control.BodyContentDisplay.Controls.Add(new LiteralControl(this.Content));
   string strUpdatedContent = this.Page.Request.Form[this.ClientID + "content"];
   if ((strUpdatedContent != null) && (this.Content != strUpdatedContent))
    this.Content = strUpdatedContent;
     SPWebPartManager currentWebPartManager = (SPWebPartManager)WebPartManager.GetCurrentWebPartManager(this.Page);
     Guid storageKey = currentWebPartManager.GetStorageKey(this);
    catch (Exception exception)
     Label child = new Label();
     child.Text = exception.Message;
   if (this.IsInEditMode)
    this.Page.ClientScript.RegisterHiddenField(this.ClientID + "content", this.Content);

    control.BodyContentDisplay.Visible = false;

    this.emptyPanel.TagName = "DIV";
    this.emptyPanel.Style.Add(HtmlTextWriterStyle.Cursor, "hand");
    this.emptyPanel.Controls.Add(new LiteralControl("Click here to Edit"));
    this.emptyPanel.Style.Add(HtmlTextWriterStyle.TextAlign, "center");
    base.Attributes["RteRedirect"] = this.editableRegion.ClientID;
    ScriptLink.RegisterScriptAfterUI(this.Page, "SP.UI.Rte.js", false);
    ScriptLink.RegisterScriptAfterUI(this.Page, "SP.js", false);
    ScriptLink.RegisterScriptAfterUI(this.Page, "SP.Runtime.js", false);
    this.editableRegion.TagName = "DIV";
    this.editableRegion.InnerHtml = this.Content;
    this.editableRegion.Attributes["class"] = "ms-rtestate-write ms-rtestate-field";
    this.editableRegion.Attributes["contentEditable"] = "true";
    this.editableRegion.Attributes["InputFieldId"] = this.ClientID + "content";
    this.editableRegion.Attributes["EmptyPanelId"] = this.emptyPanel.ClientID;
    this.editableRegion.Attributes["ContentEditor"] = "True";
    this.editableRegion.Attributes["AllowScripts"] = "True";
    this.editableRegion.Attributes["AllowWebParts"] = "False";
    string script = "RTE.RichTextEditor.transferContentsToInputField('" + SPHttpUtility.EcmaScriptStringLiteralEncode(this.editableRegion.ClientID) + "');";
    this.Page.ClientScript.RegisterOnSubmitStatement(base.GetType(), "transfer" + this.editableRegion.ClientID, script);

  // Properties
  public string Content
    return this._content;
    _content = value;

STEP 5: Your CS file will also need the following using statements at the top:
using System;
using System.ComponentModel;
using System;
using System.Globalization;
using System.Collections.Generic;
using System.ComponentModel;
using System.Xml.Serialization;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebPartPages;
using Microsoft.SharePoint.WebControls;
using Microsoft.Web.CommandUI;

STEP 6: The use of Microsoft.Web.CommandUI means we need to add a project reference to the appropriate dll.
  • Right click on the project and Add Reference.
  • Click Browse and find: C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI\Microsoft.Web.CommandUI.dll

That's all! Build it, edit the page, insert a web part and the part will be in the custom folder. Edit the project's .webpart file and the Elements.xml file if you want to change the name, description and group that the webpart belongs to.

After this, you can extend and style the control to your heart's content. Some ideas:

1. Use CSS to style the DCContentBlock and DCContent classes
2. Add your own HTML to the webpart's ASCX template
3. Add editor properties to allow the user to select from some preset styling options.

I went to the additional trouble of adding editor properties by following this excellent article by Sahil Malik. When the user selects from my custom editor property drop-down, I store the preference value. I then refer to this value to append an appropriate css class to the DCContentBlock div in the WebPart's OnPreRender. Let me know if you'd like me to do a separate post on how to do that.


  1. Anonymous12:40 pm


  2. Found myself doing a very similar thing today in order to drop the control onto a custom application page - note to anyone who tries this: don't forget to set ribbon.CommandUIVisible = true!!!

  3. Anonymous1:07 pm

    Works like a charm! Saved me lots of trouble! Thanks!

  4. Anonymous4:08 pm


  5. Awesome! Thank you. I needed to do a bi-lingual Content Editor. I extended this and bingo! Thanks.

  6. Will have to test this later - but this is exactly what I am needing to do! Awesome & thank you!

  7. I have a problem with this web part. When it is included in a web part page, I edit the page put the content and then I click on "Stop Editing". The Web Part is not reflecting the changes. If I press F5 over the page, it works.

  8. Awesome! work Thank you.
    Can you provide code of custom editor properties? Thanks in advance.

  9. Anonymous3:50 pm

    Amazing work, thankyou!

    I tweaked it a bit myself to hide editableRegion when there's no content (adding display:none to the style attribute of editableRegion), and a few other things, but your work saved me days.

    @George - If you want your changes to show immediately add the following line underneath "currentWebPartManager.SaveChanges(storageKey);"

    SPUtility.Redirect(System.Web.HttpContext.Current.Request.Url.ToString(), SPRedirectFlags.Trusted, System.Web.HttpContext.Current, null);

    This will reload the page whenever the content changes, forcing the updated contents to be shown.

    Thanks again!

  10. Anonymous1:11 pm

    Great work! One thing I'm not sure about is how the user control gets deployed to the control templates folder. Typically, I would map a folder to this location in my project and build my user control there. However, can't do that with a web part.

  11. Anonymous11:08 pm

    Does this work for SharePoint 2013?

  12. Anonymous11:12 pm

    Where does the private DCContentBlockUserControl come from?

  13. Anonymous12:19 am

    The source solution would be helpful thanks!

  14. Anonymous6:34 pm

    Excellent article. Save me a loads of time.

    I noticed that the web part is rendered twice on the page. Has anyone seen this?

  15. Anonymous6:47 pm

    Please ignore the question asking about web part rendering twice. The issue was my fault. I had mistakenly added override to the CreateChildControls() method where i added the same user control. My mistake. :(

  16. can this work for SP 2013?

  17. thanks you for this customize,

    kindly note if you need to custom style on this control, add attribute named ["RteRedirect"] to control.BodyContentEdit control like below:

    control.BodyContentEdit.Attributes["RteRedirect"] = this.editableRegion.ClientID;

    Note: for custom style visit below link:


  18. This comment has been removed by a blog administrator.

  19. This comment has been removed by a blog administrator.

  20. Anonymous8:12 am

    I am geeting error message while built. Is there anything I need to do along with above mentioned steps

  21. Anonymous8:13 am

    I am geeting error message while built. Is there anything I need to do along with above mentioned steps

  22. I am very grateful to read your blog.I hope you would provide the great services in the field of website design and development and Search Engine Optimization. Thank for the sharing.
    Bangalore Website Design Company | Website Design Bangalore

  23. It is indeed a very tough to create professional website, especially if it is the first time. It is very important to understand the complete details related to the process of the website development. Only then it becomes easy to develop.

    Cado Magenge.

  24. Web Design Sydney: It is a great sharing...I am very much pleased with the contents you have mentioned. I wanted to thank you for this great article.Logo Design Sydney, Logo Design in Coimbatore, Brochure Design in Coimbatore

  25. Lovely blog with much more interesting article, I will keep on reading your update. Thanks for the share Ear Plugs for Swimming Ear plugs for Sleeping Custom Ear Plugs

  26. It is the probability of including developments (HTML tags or scripts), particularly exercises which allow to add of the substance to the place that we require in the file on which we are satisfying desires.

    Perusahaan jasa seo | seo service company

    jakarta seo perusahaan | jakarta seo company


  27. Web Design Sydney: It is a great sharing...I am very much pleased with the contents you have mentioned. I wanted to thank you for this great article. .Logo Design Sydney,Logo Design in Coimbatore

  28. I would like to appreciate your work and would like to tell to my friends.Custom web design

  29. This article is very informative and helpful. Thank you for sharing!

  30. A basic blog by the planner with stores of supportive post nearby building and change. A commitment of thankfulness is all together for share quality data with us.
    eCommerce Website developers companies in bangalore
    experts of web developer companies in bangalore

  31. Thanks for this wonderful post and hoping to post more of this! Please Visit:

    minneapolis seo company
    minneapolis seo agency
    minneapolis web design company

  32. Fixx Group is a top leading website development company in Bangalore, Karantaka. we are providing cheapest web development service company in Bangalore and all over India.
    website developers in Bangalore | Website Development Companies Bangalore


Comments are very welcome unless you're a spammer, in which case you should probably kill yourself.

If I helped you out today, you can buy me a beer below. Cheers!