Writing custom editors for Sharepoint 2007 and ASP.NET 2.0 WebParts

Posted on 6/30/2006 @ 8:42 PM in #SharePoint by | Feedback | 30082 views

Let me begin by telling you the good news first - You write an ASP.NET 2.0 WebPart - it _is_ a Sharepoint 2007 WebPart.

Not only that, all editors you write for ASP.NET 2.0 Webparts - automagically show editability in Sharepoint 2007 - can't beat that with a stick, now can you?

So lets get started. Writing a simple Webpart is simply a matter of either implementing the IWebpart interface ~ to give some behavior to GenericWebPart, or inheriting from the WebPart class - which is a true WebPart. If you had any public properties on your WebPart, you could decorate them with the WebBrowsable(true) attribute. By doing so, they become automatically editable in the PropertyGridEditorPart.

What does that mean?

That means - if you had a property like below -

[WebBrowsable(true)]
[Personalizable(PersonalizationScope.Shared)]
public string TeaserText
{
    get { return teaserText; }
    set { teaserText = value; }
}

And if you had something like the below in your aspx –

<asp:EditorZone ID="EditorZone1" runat="server">
    <ZoneTemplate>
        <asp:PropertyGridEditorPart ID="PropertyGridEditorPart1" runat="server" />
    </ZoneTemplate>
</asp:EditorZone>

This simply translates into a UI as shown below at runtime (assuming you've done everything else correctly, and the below shows a number of properties - TeaserText is at the bottom) -

Okay good. So as you know I'm working on a WebSite-Setter-Upper-Framework, that I choose to call "SpareJoint". SpareJoint because it is based on the ASP.NET 2.0 Webpart framework, and it is a much simpler subset of Sharepoint to be used in situations such as hosting providers, or where you don't/cannot deal with full blown sharepoint, or you need a much finer level control than Sharepoint offers. My Website - www.winsmarts.com currently runs on SpareJoint, and I intend to finish it and release the framework soon-ish :) as open source. (Woohoo!!)

Also, SpareJoint is written using Atlas and ASP.NET 2.0 Webparts - so it's turning out real good. Give me about a month to release it, and contact me if you are interested in beta testing or contributing to the project.

So as you can see from my website, every page follows a "theme". Well, the technical word for that in ASP.NET 2.0 isn't theme - it's Master Page. In fact, the 3 columns you see are ContentPlaceHolders, with default content in the two sidebars, and a blank space in the middle i.e. the "mainContent" area. You could simply rewrite the master page if you wanted a different UI.

Great, so lets get started. (finally)

My WebSite, www.winsmarts.com has a master page. I've created a default.aspx (this page ain't a real aspx in SpareJoint, it's all URL Rewrite magic and templates - cool huh?), where I've overridden the "mainContent" area and left the sidebars as is. This page, now when it runs looks like below -

The big blank grey space you see inside, is now supposed to be filled with "Content Blocks", which you can see on my website - www.winsmarts.com.

One content block looks like as below -

This, with some simple stylesheet magic, is being rendered by HTML that looks like below - (again, you can completely customize the stylesheet/html/whatevertheheckuwant in the framework) -

<div class="container">
    <h1>Headline</h1>
    <p class="teaser">Teaser text</p>
    <p>Regular text and other markup.</p>

</
div>

.. also, what I didnt' show in the HTML are the image, and the "more" link - which are again fully controlled by css - in other words, they are very very simple HTML.

The upshot of the above simply is that my "Render" method in the WebPart becomes damn easy. (I am not going to talk about "How to write a Webpart" in this blogpost).

Now here comes the funky part. The in built PropertyGridEditorPart will work just fine for "single line" edits - the title, teaser text, the image src, etc. But the "Body" ideally needs a heavy duty editor ~ such as a multiline TextArea, or the telerik r.a.d. Editor.

So you need to write a Custom Editor. (Whew we're finally getting to the point).

Here's how you do that -

1. Implement the IWebEditable interface on your WebPart, this requires you to implement two methods, here is my implementation -

#region IWebEditable Members

EditorPartCollection IWebEditable.CreateEditorParts()
{
    List<EditorPart> editors = new List<EditorPart>();
    editors.Add(new HtmlEditor());
    return new EditorPartCollection(editors);
} 

object IWebEditable.WebBrowsableObject
{
    get { return this; }
} 

#endregion

The "CreateEditorParts" method is what "Fills - in" the custom Editor's collection. So you *could* have more than one Editor for your WebPart - how neat !! :)

The WebBrowsableObject - well that is what is being edited. This could have been a business object, should that be your architecture. In my case, I am returning the Webpart itself.

I've skipped the full implementation of the WebPart, as the rest is simply "Properties" and "Render" that generates HTML similar to the div thingie I showed above. Yes it will be a part of the final SpareJoint framework anyway, so why bother.

2. So as you can see, I am creating a "new HtmlEditor" above. Well, WTF is that? THAT is my CuistomEditor :). So go ahead and add a class called "HtmlEditor" and make it inherit from "EditorPart".

The EditorPart will require you to implement two methods -

ApplyChanges ~ to copy content from Editor to Webpart, and
SyncChanges ~ to copy content from WebPart to Editor.

Both these methods are called by the WebParts framework at appropriate times. Here is my implementation for the EditorPart -

 

public class HtmlEditor : EditorPart
{
    private TextBox htmlContentTxt;
 
    public HtmlEditor()
    {
        this.ID = "BodyEditor";
        this.Title = "Content Block Body";
    }
 
    protected override void CreateChildControls()
    {
        htmlContentTxt = new TextBox();
        htmlContentTxt.TextMode = TextBoxMode.MultiLine;
        htmlContentTxt.Rows = 6;
        htmlContentTxt.Width = new Unit("100%");
        Controls.Add(htmlContentTxt);
    } 

    public override bool ApplyChanges()
    {
        EnsureChildControls();
        ContentBlock part = WebPartToEdit as ContentBlock;

        if (part != null)
        {
            part.Body = htmlContentTxt.Text;
        }
        else
        {
            return false;
        }

        return true;
    }

    public override void SyncChanges()
    {
        EnsureChildControls();
        ContentBlock part = WebPartToEdit as ContentBlock;
        if (part != null)
        {
            htmlContentTxt.Text = part.Body;
        }
    }
} 

Great, now build this, and register this Control in your ASPX/Masterpage (SpareJoint will have a much better deployment process than "Edit your ASPX" - which is kinda icky). This "registering" stuff is done by doing the below -

<%@ Register Assembly="Winsmarts.SpareJoint.WebParts.MySite.ContentBlock" Namespace="Winsmarts.SpareJoint.WebParts.MySite.ContentBlock"   TagPrefix="cc5" %>

and

.. in the DeclarativeCatalogPart (which sits inside CatalogZone) -

<cc5:ContentBlock ID="ContentBlock" runat="server" Title="Winsmarts Content block" Description="This is the content block widget for my site." />

Great, fire up the browser, and lets start using this WebPart. First set the page in "Catalog Mode" and add a few instances of the WebPart (in SpareJoint, this editing thingie is done via Atlas, so the user experience is so much better). The two webparts instances I've added, after having been added look like the below -

Now go ahead and set the page's WebpartManager in Edit Mode, and an "Edit" button appears next to the WebParts as shown below -

Click on "Edit" and the EditorZone appears (yours may look different, the below screenshot is highly stylized, plus it sits in an Atlas thingie - more on that sometime later). Go ahead and fill in the various details :) -

With these details filled, click "OK" or "Apply" and bingo, your WebPart now renders like this -

Great, but something looks wrong - this part is below, and it should be at the top. Well - just drag drop to the top and fill the second part in as well as shown below -

Great !! Now add a third WebPart and fill in details about INETA to match the looks of my website, logout, and browse the site, looks a bit like ~

Now ain't that COOOOL??? Gotta say, with this little bit upfront effort, I now have a site that I can fully create and manage through my browser ~ can't ask for more than that, now can I?

And the best part - This editor, and WebPart, will work in Sharepoint 2007 AS-IS - No Code change required, only a slighty different deployment process as described here.

 

Sound off but keep it civil:

Older comments..


On 8/22/2007 1:51:00 PM Rich Lund said ..
Great post Sahil! Either my googling skills ain't what they used to be or there are very few decent descriptions of how to just get a multi-line textbox property. Thanks!


On 3/6/2008 1:39:36 AM Nadeem said ..
Hi Sahil,


Its been a wonderful blog to gone through with,but i m stuck up in a situation,Please help me out.

I have created web part which uses another application dll,i can say third party dll.While deploying it on the MOSS site, i m getting error.Please provide me a link or way out for deploying web part with another application dll.

Thanks


Nadeem


On 5/29/2008 1:02:53 PM Misha said ..
Hi, really helpful article, except i do have a doubt... I did create a custom web part and added in the property grid as you had suggested, but my property grid shows only the "TeaserText", are the Image links and the other fields in there not default? Of course, i am working on a ASP .NET application, not sharepoint..


On 7/16/2008 5:52:33 AM Chris said ..
ASP.Net web parts may be Sharepoint web parts, however there is a catch.


The default web part pages in Sharepoint require the class to be a Sharepoint specific web part not a vanilla asp.net web part.


On 7/16/2008 4:59:31 PM Sahil Malik said ..
Ummm .. no Chris. SP's default webpart pages will perfectly well accept an ASPNET 2.0 webpart, in fact that is what you should be writing (inheriting from) - the aspnet webpart class, not the sharepoint webpart class.

SM


On 9/1/2008 4:32:15 AM Nimisha said ..
Hi Sahil,

I have a scenario, where my editor part needs to enable Apply/Ok buttons on the editor pane, only when user has filled certain pre requisite fields.

Is there a way I can disable them?

Thanks in advance,


Nimisha