TweetPart This is the second part of the Web Part Properties series. The last post walked through the basics on how to make editable properties on a Web Part. As a sample I used a Web Part that displayed tweets from Twitter - called TweetPart.

Using the standard approach, by marking the properties using specific attributes, we made the Web Part editable as we wanted. But the user experience, for editing, was not optimal. First of all the properties we wanted to edit was located in their own category at the bottom, not that easy to find for inexperienced/untrained users. Secondly the properties has dependencies and requires validation.

To WebPart or WebPart

When developing Web Parts for Windows SharePoint Services 3.0 or Microsoft Office SharePoint Server 2007 you have two different Web Part classes to choose from:

Which one should I use when building Web Parts? WSS 3.0 supports both…

Tip: When checking out samples for Web Parts, note which class is used. Most samples on MSDN are using the older construct.

The first class is a part of ASP.NET 2.0 and the other one is from the Microsoft.SharePoint.dll library. The latter is there to maintain backwards compatibility with SharePoint 2003 (built upon .NET 1.1, which did not have a built-in WebPart class). I strongly recommend using the ASP.NET 2.0 WebPart, since it’s a newer construct and will probably still be used in the upcoming SharePoint 14. The ASP.NET WebPart is still in the new .NET Framework 4.0, according to the PDC 08 pre-release bits, and I doubt that Microsoft will introduce a third WebPart class. What will happen to the SharePoint WebPart class is not known (to me).

Note: Even though the two classes share the same functionality they differ in how to create custom editing tool panes, how Web Part connections work and how their Web Part Xml definitions look like.

The EditorPart class

ASP.NET 2.0 contains an abstract class called EditorPart, this class is used with the ASP.NET 2.0 WebPart class to create customized tool panes. By inheriting from this control you can customize the look and functionality of the tool pane and use standard ASP.NET constructs such as auto post backs, validations etc.

Tip: since this is standard ASP.NET 2.0 techniques you can have this running outside of SharePoint if you implement your own Web Part based web site.

In our TweetPart sample we had a drop-down, with the different display modes. Depending on the display mode selection the two text boxes should be shown or not. To achieve this we can create a new EditorPart class and replace the auto-generated Twitter category tool pane. Standard attribute properties, with automatic tool panes, can of course be combined with EditorParts - and in this sample we will leave the count of tweets as a standard attributed property.

First of all we create a new class which inherits from System.Web.UI.WebControls.WebParts.EditorPart. In this class you have to override two abstract methods and add the controls that you are going to use.

Add controls

The controls are added in the CreateChildControls method. This is where you should place most of your control logic, in editor parts, web parts etc.

Note: Make sure you understand the ASP.NET 2.0 event model!

I have one select list and two textboxes, representing the different web part properties here.

protected ListBox m_lbModes;
protected TextBox m_tbUsername;
protected TextBox m_tbSearchString;

protected override void CreateChildControls() {
    // Add controls here
    m_lbModes = new ListBox();
    m_tbUsername = new TextBox();
    m_tbSearchString= new TextBox();
    foreach (string mode in Enum.GetNames(typeof(TwitterTimeLineMode))) {
        m_lbModes.Items.Add(mode);
    }
    this.Controls.Add(new LiteralControl("<b>Mode</b><br/>"));
    this.Controls.Add(m_lbModes);
    this.Controls.Add(new LiteralControl("<br/><b>Username</b><br/>"));
    this.Controls.Add(m_tbUsername);
    this.Controls.Add(new LiteralControl("<br/><b>Search string</b><br/>"));
    this.Controls.Add(m_tbSearchString);

    base.CreateChildControls();
    this.ChildControlsCreated = true;
}

SyncChanges

The SynChanges method is used by the EditorPart to get the values from the Web Part into the Editor Part.

public override void SyncChanges() {
    EnsureChildControls();
    TwitterWebPart twitterWebPart = (TwitterWebPart)this.WebPartToEdit;
    if (twitterWebPart != null) {
        // get values from WebPart
        m_lbModes.SelectedValue = twitterWebPart.Mode.ToString();
        m_tbUsername.Text = twitterWebPart.Username;
        m_tbSearchString.Text = twitterWebPart.SearchText;
    }
    return;
}

ApplyChanges

The ApplyChanges method is executed when you click Ok or Apply and is used to set the property values of your Web Part. SyncChanges is always called directly after the ApplyChanges method, to make sure that the properties are in sync.

public override bool ApplyChanges() {
    EnsureChildControls();
    TwitterWebPart twitterWebPart = (TwitterWebPart)this.WebPartToEdit;
    if (twitterWebPart != null) {
        twitterWebPart.Mode = (TwitterTimeLineMode)Enum.Parse(typeof(TwitterTimeLineMode), m_lbModes.SelectedValue);
        twitterWebPart.SearchText = m_tbSearchString.Text;
        twitterWebPart.Username = m_tbUsername.Text;
    }
    return true;
}

Modify the WebPart class

Now we have to tell the web part that it should use this editor part, instead of the attributed properties. First of all we want to get rid of the automatic interface for the properties, this is done by removing the Personalizable attribute.

Note: Just removing the Personalizable attribute and none of the others (WebBrowsable etc), will still allow you to configure these properties using tools such as SharePoint Designer.

Note: Values of properties in the editor part have precedence over automatic generated properties.

IWebEditable interface

Now only one thing remains and that is to expose the editor part from the web part. To do this you have to make your web part class inherit from the IWebEditable interface and implement it. Don’t forget to add an Id to the EditorPart class.

EditorPartCollection IWebEditable.CreateEditorParts() {
    // control the editorparts
    List editors = new List();
    TwitterEditorPart editorPart = new TwitterEditorPart();
    editorPart.ID = this.ID + "_editorPart";
    editors.Add(editorPart);
    return new EditorPartCollection(editors);

}

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

The CreateEditorParts method is used to tell the web part zone what editor parts you will show, in this case we only have one. But more advanced web parts may require that you have several.

Tip: You can use the WebPartManager.Personalization status to add different editor parts. For example you can have one for the Shared scope and another for the User scope

The WebBrowsableObject property is used to get a reference to the Web Part, just return the this object in your editor parts. This property is used by the editor part to get which web part to edit, via the WebPartToEdit method.

The result

If we now compile and test this web part we will have an interface that looks something like this. Now we have the edit part located at the top of the tool pane, instead of below - easier to find.

First…

It works, but looks awful.

Make it more user friendly

We only want the search string to be visible when the Search mode is selected, and the same for the username and User mode, so we have to hook up some events to this editor part. This is standard ASP.NET control programming and easily done.

To make it look a bit nicer we reuse some SharePoint CSS classes and I also set a title of the editor part…

protected override void CreateChildControls() {

    this.Title = "TweetPart properties";

    // Add controls here
    m_editorPanel = new Panel();
    m_editorPanel.CssClass = "ms-ToolPartSpacing";
    this.Controls.Add(m_editorPanel);

    m_modesPanel = new Panel();            
    m_modesPanel.Controls.Add(new LiteralControl("<div class='UserSectionHead'>Mode</div>"));
    m_modesPanel.Controls.Add(new LiteralControl("<div class='UserSectionBody'><div class='UserControlGroup'><nobr>"));
    m_lbModes = new ListBox();
    m_lbModes.CssClass = "UserInput";
    m_lbModes.Width = new Unit("176px", CultureInfo.InvariantCulture);
    foreach (string mode in Enum.GetNames(typeof(TwitterTimeLineMode))) {
        m_lbModes.Items.Add(mode);
    }
    m_lbModes.AutoPostBack = true;
    m_lbModes.SelectedIndexChanged += new EventHandler(m_lbModes_SelectedIndexChanged);
    m_modesPanel.Controls.Add(m_lbModes);
    m_modesPanel.Controls.Add(new LiteralControl("</nobr></div></div>"));
    m_editorPanel.Controls.Add(m_modesPanel);

    m_searchPanel = new Panel();
    ...
    m_editorPanel.Controls.Add(m_searchPanel);


    m_usernamePanel = new Panel();
    ...
    m_editorPanel.Controls.Add(m_usernamePanel);

    ...
}

I use a set of Panel objects, which I hide depending on the selection in the list box. The list box has an event handler for when the selected index changes and reloads the editor part, I also made it automatically post back when the user selects anything in the list box. Check out the source (provided below) for more information.

Now it looks like this, a whole lot nicer. In upcoming posts I will show you have to make it even one notch better, using templates and less code.

Final…

And it works as it should. Also note that we still have the tweet count property as a automatic property, when in shared mode.

Try it!

If you would like the code, it’s available here but if you are interested in using the TweetPart you can download the WSP here. Visual Studio 2008 and STSDev are required to compile the code.

Next part…

Next part in this series, will focus on how to further improve the experience using Web Part properties and Editor Parts.

Until next time…

Technorati tags: WebPart, EditorPart, WSS, SharePoint, .NET, ASP.NET