Add to My Yahoo! | Google Reader or Homepage | Add to Windows Live | Add to Windows Live Alerts

Wictor Wilén

Microsoft Certified Master (MCM) - SharePoint 2010 | Microsoft Most Valuable Professional (MVP) - SharePoint Server MVP | Author

Web Part Properties - part 2 - Editor Parts

Posted at 2009-01-11 10:13 by Wictor Wilén in .NET , C# , SharePoint , Web Parts with 31 comments.

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…

 

Comments and trackbacks

#  Web Part Properties - part 3 - the .webpart file by Trackback
Screenshot from websnpr 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...
#  Web Part Properties - part 5 - localization by Trackback
Screenshot from websnpr 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...
#  Web Part Properties - part 6 - Complex Properties by Trackback
Screenshot from websnpr 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 ...
#  Editor Localization by Ted
Screenshot from websnpr 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!
#  Re: Editor Localization by Wictor
Screenshot from websnpr 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
#  Web Part Properties - part 6 - Complex Properties by Trackback
Screenshot from websnpr To end my series of Web Part properties I would like to show how to store more complex values than just
#  Web Part Properties - part 5 - localization by Trackback
Screenshot from websnpr If you are building a reusable web part that you would like to sell or give away you should look into
#  Showing Custom editorpart after the default editorparts by Charu
Could you please tell me how can I show the custom editor part after the default parts such as Appearance and Layout editor parts?
#  Error Adding WebPart by Tom Resing
Screenshot from websnpr 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?
#  @Tom by Wictor
Screenshot from websnpr I thought I fixed that one...anyways I'll create a CodePlex project for it and slam up the correct code.
#  EditorPart / .webpart file by Reggie
Screenshot from websnpr If I have a property that has an editorpart can I still set its value with a .webpart file. When I debug its value is null. Any thoughts?
#  Spreading some SharePoint Love to EditorPart by Trackback
Screenshot from websnpr EditorPart. Such a lonely guy in SharePoint land. Back in the 2003 era (remember that?) we had this thing
#  @Reggie by Wictor
Screenshot from websnpr Yes, you can set the values in the .webpart file. Where is your value null? Have you implemented the SyncChanges() method?
#  software developers by software developers
Screenshot from websnpr Cool, you nailed it so well. I loved the way you described working with webparts Thanks for bringing this up
#  @software developers by Wictor
Screenshot from websnpr Thanks a lot! Comments like this makes me wanna write some more...
#  Thank You! by Anonymous
Screenshot from websnpr You're code is heavensent. :)
#  createchildcontrols and applychanges by Steve
Screenshot from websnpr 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?
#  @Steve by Wictor
Screenshot from websnpr 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
#  @Wictor by Steve
Screenshot from websnpr 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.
#  @Wictor by Steve
Screenshot from websnpr 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.
#  thanks by gowri sankar
Screenshot from websnpr thank you very much.
#  actual by orange county
Screenshot from websnpr Your topic chosen really stickes as it is so actual that people cannot help discussing it every day. Hopefully, we all can get some changes made to that concerning issues.
#  well done! by construction games
Screenshot from websnpr 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.
#  Thanks for the implication. by compound interest formula
Screenshot from websnpr There one thing I want to thank you for your excellent info you posted in this article. I like find out the code, so I download the WSP in the website you posted there. It is interesting for me to read these codes. Thanks
#  Thanks by SEO UK
Screenshot from websnpr 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;
#  @SEO UK by Wictor
Screenshot from websnpr Hi, check this post: http://www.wictorwilen.se/Post/Web-Part-Properties-part-6-Complex-Properties.aspx
#  Position of Editor Part by SAP
Screenshot from websnpr Hi Wictor, This is a really awesome post.But I have a doubt.How to make the editor part appear at the bottom of the tool pane instead of top?
#  Great Article by tanmayee
Thank you so much..it is very neat and clearly explained..thanks again.
#  Re by Vetement Grossesse
Screenshot from websnpr While Asp.Net web development there are situations when you want to call a server side function (Web Method written in c# say) from client side i.e. using Javascript.
#  Templates and less code by dunxd
Screenshot from websnpr 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?
#  @dunxd by Wictor
Screenshot from websnpr 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)
Make a comment on this post:
Subject:  

Your name:  
Your Url:  
Note: submissions may have to be approved before being visible, so don't submit your comment multiple times.