This post is migrated from previous hosting provider. There are still some issues with old posts. Please make a comment on this post with any issues.

Web Part Properties - part 2 - Editor Parts

Tags: .NET, C#, SharePoint, Web Parts

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…

41 Comments

  • Trackback said

    This is the third part of my Web Part Properties series and this post will focus on the .webpart file. Every SharePoint developer have seen it and perhaps edited it, but what is the purpose of the fil...

  • Trackback said

    If you are building a reusable web part that you would like to sell or give away you should look into localizing your web part. The localization support is great with .NET 2.0, using resource files, a...

  • Trackback said

    To end my series of Web Part properties I would like to show how to store more complex values than just strings or integers. What happens if you would like to store a more complex object; an array or ...

  • Ted said

    Could you show how to provide localization for the Editor Part? I have been running into trouble and I have also read that it is different for MOSS vs WSS. I noticed in part 5 you indicated this was relatively simple. Could you elaborate a little more? Thanks!

  • Wictor said

    Hi Ted, There should be no difference in WSS and MOSS, both is built upon ASP.NET 2.0. Here is a link to a great post that will help you out: http://weblogs.asp.net/dwahlin/archive/2009/01/20/custom-asp-net-server-controls-and-language-localization.aspx /WW

  • Tom Resing said

    Wictor, thanks for sharing this post and making the code available. I like your twitter example, so I download the code and compiled it. I got an error adding the web part, but it is easily fixed. You have the Personalizable Attribute commented out on some of the properties. Removing the comment and redeploying fixes the error adding. Would you object to creating a CodePlex project for this?

  • Steve said

    Hi, thanks for this. I'm having an issue where createchildcontrols is being called before applychanges after hitting ok/apply and I have to refresh the page to see the changes made in the editor part. Any ideas for what i can do?

  • Wictor said

    Hi Steve, this is correct and its the way it works. You could move the logic that is dependant on your ApplyChanges to the OnPreRender to get it to work immediatley. Also check this post out http://www.wictorwilen.se/Post/SharePoint-Web-Part-Event-Flow-in-detail.aspx

  • Steve said

    Wictor, thanks very much for your reply. I moved the code eg: GenericWebPart oPart = (GenericWebPart)WebPartToEdit; CUSUMChart control = (CUSUMChart)oPart.ChildControl; control.seriesID = _txtSeries.Text; to onPreRender but my chart still displays the old value until a refresh. From the user control i reference base.Series to get the id to use to render an MS chart, but this id is not set to the new id until the applychanges() method is called. Is there a way I can reference the value of the _txtSeries.Text (control in editor part) from my user control or a way I can test that ok/apply button was clicked so i can force applychanges call from createchildcontrols ensuring my base values are updated and available to my user control? thanks again.

  • Steve said

    Wictor, thanks very much for your reply. I moved the code eg: GenericWebPart oPart = (GenericWebPart)WebPartToEdit; CUSUMChart control = (CUSUMChart)oPart.ChildControl; control.seriesID = _txtSeries.Text; to onPreRender but my chart still displays the old value until a refresh. From the user control i reference base.Series to get the id to use to render an MS chart, but this id is not set to the new id until the applychanges() method is called. Is there a way I can reference the value of the _txtSeries.Text (control in editor part) from my user control or a way I can test that ok/apply button was clicked so i can force applychanges call from createchildcontrols ensuring my base values are updated and available to my user control? thanks again.

  • construction games said

    In part2 of Web Part Properties, you has a great description on Editor Part. Here I have a helpful and informative news. I am going to bookmark this one on my site to share with my friends. Thank for your kind post. Coming on the excellent job in the next time.

  • SEO UK said

    would like to show how to store more complex values than just strings or integers. What happens if you would like to store a more complex object;

  • dunxd said

    Excellent tutorial. Thanks! You say "In upcoming posts I will show you have to make it even one notch better, using templates and less code." Did you ever write this?

  • Wictor said

    Hi, unfortunatley not. Instead it ended up in two other forms - the book that is about to be published and the code that is used in ChartPart (chartpart.codeplex.com)

  • Andrew said

    I'm still trying to find myself around ASPNET 2.0. However, this article of yours can help me understand little by little on how this can help me with my own SEO endeavors. Hope I can have everything straightened out for me. Thank you very much!

  • Barbara Brown said

    I really like this tutorial of yours as it explains all in detail especially this tip that you shared: "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." Thanks for the information!

  • Lucas Patel said

    There are two different Web Part classes to choose from? I thought there were four. But, anyway, thanks for this information. I really appreciate it very much the way you explain this in plain English!

Comments have been disabled for this content.

AWS Tracker

About Wictor...

Wictor Wilén is a Director and SharePoint Architect working at Connecta AB. Wictor has achieved the Microsoft Certified Architect (MCA) - SharePoint 2010, Microsoft Certified Solutions Master (MCSM) - SharePoint  and Microsoft Certified Master (MCM) - SharePoint 2010 certifications. He has also been awarded Microsoft Most Valuable Professional (MVP) for four consecutive years.

And a word from our sponsors...

SharePoint 2010 Web Parts in Action