Wrox Home  
Search
Real World SharePoint 2007: Indispensable Experiences From 16 MOSS and WSS MVPs
by Scot Hillier (Editor), Robert Bogue, Adam Buenz, Andrew Connell, Stacy Draper, Luis Du Solier Grinda, Todd Klindt, Jason Medero, Dustin Miller, Shane Perran, Joris Poelmans, Heather Solomon, Nick Swan, Jan Tielens, Mike Walsh, Shane Young
August 2007, Paperback


Excerpted from Real World SharePoint 2007: Indispensable Experiences From 16 MOSS and WSS MVPs

Developing SharePoint 2007 Web Parts

BY JAN TIELENS

Web Parts are the building blocks of pages in SharePoint sites. Users of SharePoint sites can make use of those building blocks to determine what should be displayed on a specific page in a particular SharePoint site.

When you install SharePoint, you can make use of some out-of-the-box Web Parts straight away. Depending on whether you have Windows SharePoint Services (WSS) or Microsoft Office SharePoint Server (MOSS) as your SharePoint installation, you'll have more or less. Additionally, every SharePoint list and document library will have a Web Part counterpart that can display the contents of the corresponding list or document library.

Of course, the out-of-the-box Web Parts are not the only ones that you can use! Developers can build their own Web Parts as well and deploy them to the SharePoint server. End users won't notice the difference between the custom Web Parts and the out-of-the-box Web Parts, so Web Parts are a great way to extend SharePoint.

This article takes you through the basic steps to create your own Web Parts in various ways.

TIP
The techniques and technologies described in this article are applicable both to Windows SharePoint Services (WSS) and Microsoft Office SharePoint Server (MOSS), unless mentioned otherwise. So, in this article, mention of SharePoint should be interpreted as Windows SharePoint Services 3.0 or Microsoft Office SharePoint Server 2007.

TIP
Although you can create Web Parts making use of the SharePoint 2003 classes, and use those Web Parts in SharePoint 2007 sites, you should make use of ASP.NET 2.0 Web Parts for your new projects.

Writing the Code

A Web Part in code is just a normal .NET class, nothing more, nothing less. In Visual Studio, you can make use of the Class Library project template to write code for the Web Part class. This code will be compiled into a .NET assembly, in this case a DLL that is exactly what you need. When Visual Studio is started, create a new project and select the Class Library template (Figure 1). The name of the new project is important, so think carefully when you choose a project name. Your project name should be unique on the server on which you would like to deploy your Web Parts. Additionally, the project name will be used later when the Web Parts are deployed. Also, be aware that names in .NET are case-sensitive!

Figure 1
Figure 1: Selecting the Class Library template

TIP
A common practice to ensure unique names in .NET environments is using namespaces. If the project name is, for example, MVP.Book.WebParts, by default, all the code will be sitting in the namespace with exactly the same name.

Every Class Library project in Visual Studio can contain any number of Web Part classes, so think of the project as the container of your Web Parts.

When the new project is created, there will be one class already available: Class1.cs. In general, Class1 is not a good name for a Web Part, so rename the class to HelloWorld. The special thing about a Web Part class is the fact that the class inherits from a specific base WebPart class. This base WebPart class is available in the System.Web assembly (Figure 2). By default, the Class Library project doesn't contain a reference to this assembly, so you should add it yourself. Right-click the project node in the Solutions Explorer window and choose Add Reference. Next, select the System.Web assembly from the list.

Figure 2
Figure 2: Locating the System.Web assembly

Now the HelloWorld class can inherit from the WebPart that is available in the System.Web.UI.WebControls.WebParts namespace class.

TIP
To avoid having to type the full namespace of the WebPart base class (and other classes as well), it's a common practice to add using statements on top of your code. In this article, the common namespaces won't be prefixed.

The resulting code is probably the most basic Web Part that can be created. It's a Web Part that doesn't do anything. But because the HelloWorld class inherited from the base WebPart class, the HelloWorld Web Part already has a title bar and a border, as shown in Figure 3.

Figure 3
Figure 2: HelloWorld Web Part with title bar and border

TIP
All Web Part classes must be scoped public. A Web Part class that is not marked as public can't be used in SharePoint Web Part pages. In C#, when a new Class Library project is created, the default class Class1 is automatically set to the public scope. Unfortunately, classes that are added to the project are not scoped public automatically; the developer must add the public keyword manually!

A Web Part developer must only focus on what should happen inside the Web Part. The contents displayed inside the Web Part should be generated in the Render method of the Web Part class. This method is already implemented in the base WebPart class, so it should be overridden in the HelloWorld WebPart class. This is the default implementation:

protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
    base.Render(writer);
}

The only parameter of the Render method is the writer parameter, which is of the type HtmlTextWriter. You should use this parameter to write HTML that will be rendered inside the Web Part. It's important to write valid HTML with the writer parameter, because invalid HTML is accepted as well, so it could break the Web Part page. The HelloWorld Web Part should display fixed text, which is formatted as a title:

protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
    writer.Write("<h1>Web Parts Rock!</h1>");
}

TIP
It's not recommended to write HTML tags in plain strings as displayed in the previous example. Later in this article, I discuss the proper way to generate HTML. The purpose of this example is to show the real basics.

For now, the code is sufficient. It is a Web Part that displays fixed text. Before you can deploy this Web Part, the project must be built. So, the assembly (DLL) is generated. There are many ways to trigger the build process in Visual Studio, such as with the Build menu, using the Ctrl+Shift+B key combination, and so on.

The complete contents of the Class1.cs looks like this:

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls.WebParts;
namespace BasicWebParts
{
    public class HelloWorld: WebPart
    {
        protected override void Render(
                           System.Web.UI.HtmlTextWriter writer)
        {
            writer.Write("<h1>Web Parts Rock!</h1>");
        }
    }
}

Using Controls in Web Parts

In the previous HelloWorld Web Part example, the Web Part code generated HTML by using a string. It is quite obvious that generating HTML for more complex user interfaces can be complicated. This section examines using controls in Web Parts to simplify the generation of HTML code in Web Parts:

The .NET Framework has lots of Web controls that can be used in Web Parts, including Button, Textbox, Label, and so on. Most of those user controls are residing in the System.Web.UI.WebControls namespace. The advantage of these ASP.NET Web controls is that they can generate HTML for themselves. You as a developer don't have to focus on writing HTML to render a button, for example.

Simple Calculator Example

To illustrate the use of Web controls in Web Parts, let's write a very basic example that nicely shows how to make use of a couple of Web controls, including server-side code for the event handlers of those controls. The example used will be a basic Calculator Web Part: just two textboxes for entering two numeric values, two buttons for adding and subtracting those values, and a third textbox to display the result. The focus of this Web Part won't be how to validate the entered values, and so on, but rather to just show how to build the user interface and the server-side code.

Getting Started with the SimpleCalculator Class

A Web Part using Web controls is still a normal Web Part. So, in the BasicWebParts Visual Studio project, add another class named SimpleCalculator. First, add the following using statements on top of the code:

using System.Web.UI.WebControls.WebParts;
using System.Web.UI.WebControls;
using System.Web.UI;

The using statements allow you to make use of the WebPart base class and all the ASP.NET Web controls without including the full namespace.

The second (and very important) addition to the code that must be made is the public keyword for the SimpleCalculator class. By default, in a Visual Studio 2005 C# Class Library project, the Class template doesn't include the public keyword. If the Web Part class doesn't have this public keyword, SharePoint won't be able to make use of it, so it must be added. The complete SimpleCalculator class looks like this now:

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.WebControls;
using System.Web.UI;
namespace BasicWebParts
{
    public class SimpleCalculator: WebPart
    {
    }
}

Declaring the Web Control Variables

For every Web control on the Web Part, a variable of that Web control should be declared as a member field. For the sample SimpleCalculator Web Part, there must be five variables registered (three textboxes and two buttons):

public class SimpleCalculator: WebPart
{
    TextBox tbA;
    TextBox tbB;
    TextBox tbResult;
    Button btnAdd;
    Button btnSub;
}

Overriding the CreateChildControls Method

The next step to build the SimpleCalculator Web Part is to override the CreateChildControls method from the base WebPart class. In this method, you first create of all new instances for all the Web control variables. Additionally, properties for those Web controls can be set as well. Lastly, all the Web control instances should be added to the Controls collection of the base WebPart class so that ASP.NET knows about them, and, thus, the server-side events (if they exist) will be handled correctly. Of course, it doesn't matter where the variables are instantiated and added in the CreateChildControls method. It can be in the beginning, but it can be at the end as well; they can be added even dynamically in code. Personally, I prefer to structure my code as displayed here:

protected override void CreateChildControls()
{
    tbA = new TextBox();
    tbB = new TextBox();
    tbResult = new TextBox();
    btnAdd = new Button();
    btnSub = new Button();
    tbResult.ReadOnly = true;
    btnAdd.Text = "+";
    btnSub.Text = "-";
    this.Controls.Add(tbA);
    this.Controls.Add(tbB);
    this.Controls.Add(btnAdd);
    this.Controls.Add(btnSub);
    this.Controls.Add(tbResult);
}

In the SimpleCalculator Web Part example, the ReadOnly property for the results textbox is set to true, so end users won't be able to change anything in that textbox. This is done from code. Also the text properties of the buttons are set to "+" and "-".

The order in which the controls are added to the Controls collection of the base WebPart class will determine how they are rendered later on in the Web Part. For this example, the two input textboxes should be rendered first, the two operation buttons should be rendered second, and, finally, the textbox that should display the result should be rendered.

If the controls are added like this, one after another, all of them will appear on one line. If the controls should be displayed on multiple lines, HTML break tags (
) can be added in between, as shown here:

this.Controls.Add(tbA);
this.Controls.Add(new LiteralControl("<br>"));
this.Controls.Add(tbB);
this.Controls.Add(new LiteralControl("<br>"));
this.Controls.Add(btnAdd);
this.Controls.Add(btnSub);
this.Controls.Add(new LiteralControl("<br>"));
this.Controls.Add(tbResult);

Alternatively, HTML tables, layers, and so on can be used as a more flexible way to add layout to the Web Part.

Adding Event Handlers

At this point, the code doesn't do anything except render some Web controls. The goal, of course, is to execute code when one of the operation buttons is clicked. This can be accomplished by adding event handlers for the corresponding events. These event handlers can be added in the CreateChildControls method as well.

btnAdd.Click += new EventHandler(btnAdd_Click);
btnSub.Click += new EventHandler(btnSub_Click);

The implementation of the event handlers can be done as follows. The btnAdd_Click and btnSub_Click methods are members of the SimpleCalculator class as well.

void btnAdd_Click(object sender, EventArgs e)
{
    int a = int.Parse(tbA.Text);
    int b = int.Parse(tbB.Text);
    int c = a + b;
    tbResult.Text = c.ToString();
}
void btnSub_Click(object sender, EventArgs e)
{
    int a = int.Parse(tbA.Text);
    int b = int.Parse(tbB.Text);
    int c = a - b;
    tbResult.Text = c.ToString();
}        

TIP
Once again, the focus of this Web Part is not on how to validate the input of the textboxes before the calculations are done. When this code is used in a real-life scenario, adding validation code is obviously required.

The Full SimpleCalculator Code

Now, the SimpleCalculator class is finished, and the complete combined code could look as follows:

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.WebControls;
using System.Web.UI;
namespace BasicWebParts
{
    public class SimpleCalculator: WebPart
    {
        TextBox tbA;
        TextBox tbB;
        TextBox tbResult;
        Button btnAdd;
        Button btnSub;
        protected override void CreateChildControls()
        {
            tbA = new TextBox();
            tbB = new TextBox();
            tbResult = new TextBox();
            btnAdd = new Button();
            btnSub = new Button();
            tbResult.ReadOnly = true;
            btnAdd.Text = "+";
            btnSub.Text = "-";
            btnAdd.Click += new EventHandler(btnAdd_Click);
            btnSub.Click += new EventHandler(btnSub_Click);
            this.Controls.Add(tbA);
            this.Controls.Add(new LiteralControl("<br>"));
            this.Controls.Add(tbB);
            this.Controls.Add(new LiteralControl("<br>"));
            this.Controls.Add(btnAdd);
            this.Controls.Add(btnSub);
            this.Controls.Add(new LiteralControl("<br>"));
            this.Controls.Add(tbResult);
        }
        void btnAdd_Click(object sender, EventArgs e)
        {
            int a = int.Parse(tbA.Text);
            int b = int.Parse(tbB.Text);
            int c = a + b;
            tbResult.Text = c.ToString();
        }
        void btnSub_Click(object sender, EventArgs e)
        {
            int a = int.Parse(tbA.Text);
            int b = int.Parse(tbB.Text);
            int c = a - b;
            tbResult.Text = c.ToString();
        }        
    }
}

The SimpleCalculator looks like Figure 4 at run-time.

Figure 4
Figure 4: SimpleCalculator Web Part

Manually Rendering the Web Controls

The user controls of the SimpleCalculator Web Part are rendered automatically on the Web Part's user interface because the default implementation of the Render method renders all items in the Control collection of the base WebPart class. It's also possible to override this method so that you are in full control of the rendering process. For every Web control, the RenderControl method can be called to render the corresponding HTML.

protected override void Render(HtmlTextWriter writer)
{
    this.EnsureChildControls();
    
    tbA.RenderControl(writer);
    writer.Write("<br>");
    tbB.RenderControl(writer);
    writer.Write("<br>");
    btnAdd.RenderControl(writer);
    btnSub.RenderControl(writer);
    writer.Write("<br>");
    tbResult.RenderControl(writer);
}

If the preceding code is used, the HTML break tags don't have to be added to the Controls collection. The CreateChildControls method could look as follows:

protected override void CreateChildControls()
{
    tbA = new TextBox();
    tbB = new TextBox();
    tbResult = new TextBox();
    btnAdd = new Button();
    btnSub = new Button();
    tbResult.ReadOnly = true;
    btnAdd.Text = "+";
    btnSub.Text = "-";
    btnAdd.Click += new EventHandler(btnAdd_Click);
    btnSub.Click += new EventHandler(btnSub_Click);
    this.Controls.Add(tbA);
    this.Controls.Add(tbB);
    this.Controls.Add(btnAdd);
    this.Controls.Add(btnSub);
    this.Controls.Add(tbResult);
}

This article is excerpted from Chapter 7, "Understanding Web Parts," from the book, Real World SharePoint 2007: Indispensable Experiences From 16 MOSS and WSS MVPs (Wrox, 2007, ISBN: 978-0-470-16835-6). Chapter 7 was written by MVP Jan Tielens. Jan works for the Belgian company U2U (http://www.u2u.be), which delivers developer-oriented courses focusing on Microsoft technology all around the world. His areas of expertise are Microsoft BizTalk Server, ASP.NET, and especially Information Worker technologies, including SharePoint. He became an MVP for Microsoft SharePoint Portal Server in 2005 because of his work in the SharePoint community. He's known for the famous SmartPart Web Part. Tielens is also a frequent speaker on various Microsoft events across Europe. In addition to writing your Web Part code, if you also need to learn to deploy your web part, configure Web Part trust settings, write advanced connectable Web Parts that act as providers and consumers of data, or creating Web Parts more easily with SmartPart, you'll want to read the complete Chapter 7 in the book. The other recent wrox.com article excepted from this book is Developing Sharepoint Server 2007 Publishing Sites the Smart and Structured Way, by Andrew Connell.