Creating Custom Web Parts for Project Server 2007

Summary: Learn to create a custom Web Part for Microsoft Office Project Server 2007 that you can use to display the upcoming tasks for a specified project.

Office Visual How To

**Applies to:**2007 Microsoft Office system, Project Server 2007

Joel Krist, Akona Systems

September 2007

Overview

A Web Part is a modular unit of information that has a single purpose and is a basic building block of a Web Part Page. Project Web Access uses many Microsoft Office Project Server 2007 Web Parts and can be easily extended with custom Web Parts.

Web Parts in Windows SharePoint Services 3.0 improve upon earlier versions of Web Part technologies. You can use Windows SharePoint Services 2.0 Web Parts and ASP.NET 2.0 Web Parts. You can also use Web Parts in shared Web Part Page documents in a project workspace or team site. The shared documents are stored and managed on a computer running Windows SharePoint Services that is provisioned by Project Server. This Office Visual How To article shows the creation of a custom Web Part for Project Server 2007 that you can use to display the upcoming tasks for a specified project. The code presented in this article is based on the "No PWA Reference" Web Part sample that is included in the Microsoft Office Project 2007 SDK download.

See It Creating Custom Web Parts for Project Server

Watch the Video

Length: 00:11:01 | Size: 17.2 MB | Type: WMV file

Code It | Read It | Explore It

Code It

This section walks through the six major steps to create a Web Part for Project Server 2007. The key steps are:

  1. Creating a Web Control Library project in Microsoft Visual Studio 2005.

  2. Adding the required references.

  3. Setting the Web Part assembly version number.

  4. Signing the Web Part assembly with a strong name.

  5. Adding the code that implements the functionality of the Web Part that displays upcoming tasks for a specified project.

  6. Deploying the Web Part.

Creating a Web Control Library Project in Visual Studio 2005

The following section shows how to create a Web Control library project.

To create a Web Control Library project in Visual Studio 2005

  1. Start Visual Studio.

  2. On the File menu, point to New, and then click Project.

  3. In the New Project dialog box, in the Project Types pane, select Visual C# or Visual Basic, and then select the Windows category.

  4. In the Templates pane, select Web Control Library.

  5. Type ProjectServerWebParts for the project Name.

  6. Specify a location for the project, and then click OK. Visual Studio generates a Web Control Library project with a single source file in it named WebCustomControl1.cs or WebCustomControl1.vb, depending on which language you selected in Step 3.

  7. Right-click the file in Solution Explorer, and then choose Rename. Rename the WebCustomControl1.cs or WebCustomControl1.vb source file to UpcomingTasksWebPart.cs or UpcomingTasksWebPart.vb, depending on which language you are using.

Adding the Required References

To derive a class that implements the Upcoming Tasks Web Part from the Microsoft.SharePoint.WebPartPages.WebPart class, you need to add a reference to the Windows SharePoint Services assembly.

To add a reference to the Windows SharePoint Services assembly

  1. If you are running Visual Studio on a computer that has Windows SharePoint Services or Microsoft Office SharePoint Server 2007 installed on it, use the following procedure:

    1. On the Visual Studio Project menu, click Add Reference.

    2. In the Add Reference dialog box, on the .NET tab, locate and select the Windows SharePoint Services component (Microsoft.SharePoint.dll).

    3. Click OK to add the reference.

    If you are running Visual Studio on a computer that does not have Windows SharePoint Services or Office SharePoint Server installed on it, the Windows SharePoint Services assembly is not available. In this case:

    • Copy the Microsoft.SharePoint.dll assembly file from a computer that has Windows SharePoint Services or Office SharePoint Server installed on it to a local project folder on the development computer. Following is the default assembly location on a SharePoint server:

      %ProgramFiles%\Common Files\Microsoft Shared\Web server extensions\12\ISAPI

  2. After you make a local copy of the assembly, add a reference to it by browsing for the local file as follows:

    1. On the Visual Studio Project menu, click Add Reference.

    2. In the Add Reference dialog box, on the Browse tab, navigate to the local folder containing the copy of the Windows SharePoint Services assembly.

    3. Select the Microsoft.SharePoint.dll file, and then click OK to add the reference.

The Upcoming Tasks Web Part uses the Project Server Interface (PSI) to integrate with Project Web Access. The PSI is a Web service interface that enables client applications—including Microsoft Office Project Professional 2007, Project Web Access, and back-end line-of-business applications—to access Project Server data.

To allow the Upcoming Tasks Web Part to work with the PSI, add a reference to the Project Web service. A client locates a Web service and obtains its service description by Web service discovery. The process of Web service discovery in Visual Studio involves interrogating a Web site to locate the service description, which is an XML document that uses the Web Services Description Language (WSDL). When you add a Web reference to a project, Visual Studio generates a proxy class that provides a local representation of the Web service, and allows the client code to interface with the Web service. You access methods of the Web service by calling the methods in the proxy class. The proxy class handles the communication between the client application and the Web service.

To add a Web reference to the Project Web service

  1. In Visual Studio Solution Explorer, right-click the ProjectServerWebParts project, and then click Add Web Reference.

  2. In the Add Web Reference dialog box, type the URL of the Project Web service. Following is the default location of the Web service: http://ServerName/ProjectServerName/_vti_bin/PSI/project.asmx.

  3. Click Go. Visual Studio retrieves and displays the information about the Web service.

  4. Type ProjectWS for the Web reference name, and then click Add Reference to add the Web reference to the project. Visual Studio downloads the service description and generates a proxy class to interface between the Upcoming Tasks Web Part and the Project Web service.

    Figure 1. Adding Web reference

    Adding Web Reference

Setting the Version Number of the Web Part Assembly

By default, the AssemblyVersion property of the Upcoming Tasks Web Part project is set to increment each time the Web Part is recompiled. A SharePoint Web Part page identifies a Web Part with the version number that is specified in the web.config file. With the AssemblyVersion property set to auto-increment, when you recompile and redeploy the Web Part after importing it into a Web Part Page, the SharePoint Web Part framework looks for the version number that is specified in the web.config file. If the version number does not match the deployed Web Part, an error occurs. To prevent the Web Part version number from incrementing each time you recompile, set the version number of the Upcoming Tasks Web Part assembly.

To set the version number of the Upcoming Tasks Web Part assembly

  1. On the Visual Studio Project menu, click ProjectServerWebParts Properties.

  2. On the project properties page, on the Application tab, click Assembly Information.

  3. In the Assembly Information dialog box, specify 1.0.0.0 for the Assembly Version.

  4. Click OK to save the changes.

  5. Close the project properties page.

Signing the Web Part Assembly with a Strong Name

You must sign the Upcoming Tasks Web Part assembly with a strong name before you can deploy it to the global assembly cache on the Project Server computer. A strong name consists of the assembly's identity—its simple text name, version number, and culture information (if provided)—plus a public key and a digital signature.

To assign a strong name to the Upcoming Tasks Web Part assembly in Visual Studio

  1. On the Visual Studio Project menu, click ProjectServerWebParts Properties.

  2. On the project properties page, on the Signing tab, select the Sign the assembly check box.

  3. In the Choose a strong name key file list, click <New...>.

  4. In the Create Strong Name Key dialog box, type keyfile as the key file name, and then clear the Protect my key file with a password check box.

  5. Close the project properties page.

Implementing the Upcoming Tasks Web Part

After adding the required references, setting the assembly's version number, and signing the assembly, the next step is to add the code that implements the Upcoming Tasks Web Part. Add the following Imports or using statements to the top of the source file for the Web Part. For the Visual C# case, add the using statements after the using statements that were generated by Visual Studio when it created the project.

Imports System.Drawing
Imports System.Xml.Serialization
Imports System.Net
Imports System.Data
Imports Microsoft.SharePoint.WebPartPages
using System.Drawing;
using System.Xml.Serialization;
using System.Net;
using System.Data;
using Microsoft.SharePoint.WebPartPages;

The Imports and using statements make it possible to use the classes and types defined in the referenced namespaces without having to use fully qualified namespace paths.

Replace the version of the UpcomingTasksWebPart class definition generated by Visual Studio with the following code.

<XmlRoot(Namespace:="ProjectServerWebParts")> _
Public Class UpcomingTasksWebPart
    Inherits WebPart

    ' URI of the Project Web Access server. Change to an
    ' appropriate value.
    Private PROJECT_SERVER_URI As String = _
        "http://ServerName/pwa"
    Private PROJECT_WEBSERVICE As String = _
        "/_vti_bin/psi/project.asmx"

    ' Project name in which to look up tasks.
    Private m_projectName As String = String.Empty

    ' Number of upcoming tasks to display.
    Private m_numTasks As Integer = 0

    ' The data grid to display on the Web Part.
    Private displayGrid As DataGrid = Nothing

    ' Project Web Service.
    Private projWS As ProjectWS.Project = Nothing

#Region "Properties"
    ' Handles the connection to the Project Web Service. 
    ' This is a public property so that the tool part can use
    ' the same connection.
    ReadOnly Property ProjectWS() As ProjectWS.Project
        Get
            ' If you are not connected to a project server, make the
            ' connection.
            If projWS Is Nothing Then
                projWS = New ProjectWS.Project()
                projWS.Url = PROJECT_SERVER_URI + PROJECT_WEBSERVICE
                projWS.CookieContainer = New CookieContainer()
                projWS.Credentials = _
                    CredentialCache.DefaultCredentials
            End If

            Return projWS
        End Get
    End Property

    ' These properties are exposed so the tool part can update
    ' the project name and number of tasks to display.

    <Browsable(False), _
     Category("Miscellaneous"), _
     WebPartStorage(Storage.Personal)> _
    Property ProjectName() As String
        Get
            Return m_projectName
        End Get
        Set(ByVal value As String)
            m_projectName = value
        End Set
    End Property

    <Browsable(False), _
     Category("Miscellaneous"), _
     WebPartStorage(Storage.Personal)> _
    Property NumDisplayTasks() As Integer
        Get
            Return m_numTasks
        End Get
        Set(ByVal value As Integer)
            m_numTasks = value
        End Set
    End Property
#End Region

    ' To use your own tool part, you must override the 
    ' GetToolParts method. The custom tool part provides the dynamic 
    ' list of projects to display in the drop-down list.
    Public Overrides Function GetToolParts() As ToolPart()
        Dim toolParts(2) As ToolPart

        toolParts(0) = New CustomPropertyToolPart()
        toolParts(1) = New WebPartToolPart()
        toolParts(2) = New UTToolPart()

        Return toolParts
    End Function

    ' Add an upcoming tasks grid to the Web Part content, and 
    ' add script that gets information from the Project Center Web 
    ' Part. 
    Protected Overrides Sub OnPreRender(ByVal e As EventArgs)
        Controls.Add(New LiteralControl("<b>"))
        Controls.Add(GetWebPartTitle())
        Controls.Add(New LiteralControl("</b><br/><br/>"))
        Controls.Add(GetWebPartContent())

        MyBase.OnPreRender(e)
    End Sub

    ' Get a title for the Web Part. Show the project name
    ' or the default instructions if no project is selected.
    Private Function GetWebPartTitle() As Control
        Dim titleControl As Control
        Dim titleControlLabel As Label = New Label()
        Dim projName As String = ProjectName

        titleControlLabel.ForeColor = System.Drawing.Color.Blue

        If Not projName = Nothing And Not projName = String.Empty Then
            titleControlLabel.Text = "Upcoming Tasks for Project: " + _
                projName
        Else
            projName = String.Empty
            titleControlLabel.Text = _
                "Upcoming Tasks: Web Part Configuration Directions"
        End If

        titleControl = titleControlLabel
        Return titleControl
    End Function

    ' Get a project name, find the uncompleted tasks in that project, 
    ' and show the specified number of tasks in a grid.
    Private Function GetWebPartContent() As Control
        Dim iTask As Integer = 0
        Dim projGuid As Guid
        Dim projName As String
        Dim projectDS As ProjectWS.ProjectDataSet

        Dim taskDataRow As DataRow
        Dim displayTaskDataRow As DataRow
        Dim taskRows As DataRow()

        Dim webControl As Control
        Dim webControlLabel As Label = New Label()

        displayGrid = New DataGrid()

        ' Get a DataSet of all the projects that the user has
        ' access to.
        Dim projectListDS As ProjectWS.ProjectDataSet = _
            ProjectWS.ReadProjectList()

        projName = ProjectName

        If Not projName = Nothing And Not projName = "" Then

            Dim projectRows As DataRow() = _
                projectListDS.Project.Select( _
                "PROJ_NAME = '" + projName + "'")

            If projectRows.Length > 0 Then
                projGuid = CType(projectRows(0)("PROJ_UID"), Guid)

                ' Get a DataSet of all the tasks in a project.
                projectDS = ProjectWS.ReadProject(projGuid, _
          ProjectServerWebParts.ProjectWS.DataStoreEnum.PublishedStore)

                ' Create a table with only the three columns you want 
                ' to display in the Web Part.
                Dim displayTaskDT As DataTable = New DataTable()

                displayTaskDT.Columns.Add(New DataColumn("Task Name", _
projectDS.Task.Columns(projectDS.Task.TASK_NAMEColumn.ColumnName).DataType))
                displayTaskDT.Columns.Add(New DataColumn("Start", _
projectDS.Task.Columns(projectDS.Task.TASK_START_DATEColumn.ColumnName).DataType))
                displayTaskDT.Columns.Add(New DataColumn("Finish", _
projectDS.Task.Columns(projectDS.Task.TASK_FINISH_DATEColumn.ColumnName).DataType))

                ' Filter out tasks that are already completed.
                taskRows = _
projectDS.Task.Select(projectDS.Task.TASK_PCT_COMPColumn.ColumnName + _
                    " <> 100 AND " + _
                    projectDS.Task.TASK_IS_SUMMARYColumn.ColumnName + _
                    " = 0", _
projectDS.Task.TASK_FINISH_DATEColumn.ColumnName + " ASC")

                ' Copy the number of tasks defined by the user into 
                ' the data table you created previously.
                Do While ((iTask < taskRows.Length) And _
                    (iTask < NumDisplayTasks))

                    taskDataRow = taskRows(iTask)
                    displayTaskDataRow = displayTaskDT.NewRow()

                    displayTaskDataRow("Task Name") = _
         taskDataRow(projectDS.Task.TASK_NAMEColumn.ColumnName)
                    displayTaskDataRow("Start") = _
         taskDataRow(projectDS.Task.TASK_START_DATEColumn.ColumnName)
                    displayTaskDataRow("Finish") = _
         taskDataRow(projectDS.Task.TASK_FINISH_DATEColumn.ColumnName)

                    displayTaskDT.Rows.Add(displayTaskDataRow)

                    iTask += 1
                Loop

                ' Bind the data table to the data grid you are using to 
                ' display in the Web Part.
                displayGrid.DataSource = displayTaskDT
                displayGrid.DataBind()

                displayGrid.HeaderStyle.BackColor = _
                    System.Drawing.Color.Beige
                displayGrid.HeaderStyle.HorizontalAlign = _
                    System.Web.UI.WebControls.HorizontalAlign.Center
                displayGrid.BorderStyle = _
                    System.Web.UI.WebControls.BorderStyle.None

                webControl = displayGrid
            Else
                webControlLabel.Text = _
                        "<br/>This project has no upcomming tasks " + _
                        "to display.<br/>"
                webControl = webControlLabel
            End If
        Else ' No project name is selected, so show instructions.
            Dim labelText As String = _
                    "<br/>This Web Part shows the number of tasks " + _
                    "remaining in a project."
            labelText += _
                "<br/>Configure this Web Part to select a " + _
                "project<br/>"
            labelText += _
                "and the number of tasks to display. The current " + _
                "number is "
            labelText += _
                NumDisplayTasks.ToString() + ".<br/>"

            webControlLabel.Text = labelText
            webControl = webControlLabel
        End If

        Return webControl
    End Function
End Class
[XmlRoot(Namespace = "ProjectServerWebParts")]
public class UpcomingTasksWebPart : WebPart
{
    // URI of the Project Web Access server. Change to an
    // appropriate value.
    private const string PROJECT_SERVER_URI = 
        "http://ServerName/pwa"; 
    private const string PROJECT_WEBSERVICE = 
        "/_vti_bin/psi/project.asmx";

    // Project name in which to look up tasks.
    private string projectName;

    // Number of upcoming tasks to display.
    private int numTasks;

    // The data grid to display on the Web Part.
    private DataGrid displayGrid;

    // Project Web Service.
    private ProjectWS.Project projWS = null;     

    public UpcomingTasksWebPart()
    {
    }

    #region Properties
    // Handles the connection to the Project Web Service. 
    // This is a public property so that the tool part can use
    // the same connection.
    public ProjectWS.Project ProjectWS
    {
        get
        {
            // If you are not connected to a project server, make the
            // connection.
            if (projWS == null)
            {
                projWS = new ProjectWS.Project();
                projWS.Url = PROJECT_SERVER_URI + PROJECT_WEBSERVICE;
                projWS.CookieContainer = new CookieContainer();
                projWS.Credentials = 
                    CredentialCache.DefaultCredentials;
            }
            return projWS;
        }
    }

    // These properties are exposed so the tool part can update
    // the project name and number of tasks to display.

    [Browsable(false),
     Category("Miscellaneous"),
     WebPartStorage(Storage.Personal)
    ]
    public string ProjectName
    {
        get { return projectName; }
        set { projectName = value; }
    }

    [Browsable(false),
     Category("Miscellaneous"),
     WebPartStorage(Storage.Personal)
    ]
    public int NumDisplayTasks
    {
        get { return numTasks; }
        set { numTasks = value; }
    }
    #endregion

    // To use our own tool part, you must override the 
    // GetToolParts method. The custom tool part provides the dynamic 
    // list of projects to display in the drop-down list.
    public override ToolPart[] GetToolParts()
    {
        ToolPart[] toolParts = new ToolPart[3];

        toolParts[0] = new CustomPropertyToolPart();
        toolParts[1] = new WebPartToolPart();
        toolParts[2] = new UTToolPart();

        return toolParts;
    }

    // Add an upcoming tasks grid to the Web Part content, and 
    // add script that gets information from the Project Center Web 
    // Part. 
    protected override void OnPreRender(EventArgs e)
    {
        Controls.Add(new LiteralControl("<b>"));
        Controls.Add(GetWebPartTitle());
        Controls.Add(new LiteralControl("</b><br/><br/>"));

        Controls.Add(GetWebPartContent());
        base.OnPreRender(e);
    }

    // Get a title for the Web Part. Show the project name
    // or the default instructions if no project is selected.
    private Control GetWebPartTitle()
    {
        Control titleControl;
        Label titleControlLabel = new Label();
        titleControlLabel.ForeColor = System.Drawing.Color.Blue;

        string projName = ProjectName;

        if (projName != null && projName != string.Empty)
        {
            titleControlLabel.Text = "Upcoming Tasks for Project: " + 
                projName;
        }
        else
        {
            projName = string.Empty;
            titleControlLabel.Text =
                "Upcoming Tasks: Web Part Configuration Directions";
        }
        titleControl = titleControlLabel;
        return titleControl;
    }

    // Get a project name, find the uncompleted tasks in that project, 
    // and show the specified number of tasks in a grid.
    private Control GetWebPartContent()
    {
        int iTask = 0;
        Guid projGuid;
        string projName;
        ProjectWS.ProjectDataSet projectDS;

        DataRow taskDataRow;
        DataRow displayTaskDataRow;
        DataRow[] taskRows;

        Control webControl;
        Label webControlLabel = new Label();

        displayGrid = new DataGrid();

        // Get a DataSet of all the projects that the user has
        // access to.
        ProjectWS.ProjectDataSet projectListDS = 
            ProjectWS.ReadProjectList();

        projName = ProjectName;

        if (projName != null && projName != "")
        {
            DataRow[] projectRows = projectListDS.Project.Select(
                "PROJ_NAME = '" + projName + "'");

            if (projectRows.Length > 0)
            {
                projGuid = (Guid)projectRows[0]["PROJ_UID"];

                // Get a DataSet of all the tasks in a project.
                projectDS = ProjectWS.ReadProject(projGuid,
         ProjectServerWebParts.ProjectWS.DataStoreEnum.PublishedStore);

                // Create a table with only the three columns you want 
                // to display in the Web Part.
                DataTable displayTaskDT = new DataTable();

                displayTaskDT.Columns.Add(new DataColumn("Task Name",
projectDS.Task.Columns[projectDS.Task.TASK_NAMEColumn.ColumnName].DataType));
                displayTaskDT.Columns.Add(new DataColumn("Start",
projectDS.Task.Columns[projectDS.Task.TASK_START_DATEColumn.ColumnName].DataType));
                displayTaskDT.Columns.Add(new DataColumn("Finish",
projectDS.Task.Columns[projectDS.Task.TASK_FINISH_DATEColumn.ColumnName].DataType));

                // Filter out tasks that are already completed.
                taskRows = 
projectDS.Task.Select(projectDS.Task.TASK_PCT_COMPColumn.ColumnName +
                    " <> 100 AND " +
                    projectDS.Task.TASK_IS_SUMMARYColumn.ColumnName + 
                    " = 0",
projectDS.Task.TASK_FINISH_DATEColumn.ColumnName + " ASC");

                // Copy the number of tasks defined by the user into 
                // the data table you created previously.
                while (iTask < taskRows.Length &&
                       iTask < NumDisplayTasks)
                {
                    taskDataRow = taskRows[iTask];
                    displayTaskDataRow = displayTaskDT.NewRow();

                    displayTaskDataRow["Task Name"] =
                taskDataRow[projectDS.Task.TASK_NAMEColumn.ColumnName];
                    displayTaskDataRow["Start"] =
          taskDataRow[projectDS.Task.TASK_START_DATEColumn.ColumnName];
                    displayTaskDataRow["Finish"] =
         taskDataRow[projectDS.Task.TASK_FINISH_DATEColumn.ColumnName];

                    displayTaskDT.Rows.Add(displayTaskDataRow);

                    iTask++;
                }

                // Bind the data table to the data grid you are using to 
                // display in the Web Part.
                displayGrid.DataSource = displayTaskDT;
                displayGrid.DataBind();

                displayGrid.HeaderStyle.BackColor = 
                    System.Drawing.Color.Beige;
                displayGrid.HeaderStyle.HorizontalAlign = 
                    HorizontalAlign.Center;
                displayGrid.BorderStyle = BorderStyle.None;

                webControl = displayGrid;
            }
            else
            {
                webControlLabel.Text =
                    "<br/>This project has no upcomming tasks to " + 
                    "display.<br/>";
                    webControl = webControlLabel;
            }
        }
        else // No project name is selected, so show instructions.
        {
            string labelText =
                "<br/>This Web Part shows the number of tasks " + 
                "remaining in a project.";
            labelText += 
                "<br/>Configure this Web Part to select a " +
                "project<br/>";
            labelText += 
                "and the number of tasks to display. The current " +
                "number is ";
            labelText += 
                NumDisplayTasks.ToString() + ".<br/>";

            webControlLabel.Text = labelText;
            webControl = webControlLabel;
        }
        return webControl;
    }
}

The next step is to create the ToolPart class used by the Upcoming Tasks Web Part.

To add the ToolPart class

  1. In Visual Studio Solution Explorer, right-click the ProjectServerWebParts project. On the Add menu, click Class.

  2. In the Add New Item dialog box, specify the name of the code file as UTToolPart.cs or UTToolPart.vb, depending on which language you are using, and then click Add. Visual Studio adds the class to the project.

    Figure 2. Adding the ToolPart class

    Adding the ToolPart class

  3. Replace the contents of the UTToolPart.cs or UTToolPart.vb file generated by Visual Studio with the following code.

    Imports System.Web.UI
    Imports Microsoft.SharePoint.WebPartPages
    
    ' This tool part provides the user a way to select which project's
    ' tasks to display and the number of upcoming tasks to display.
    Public Class UTToolPart
        Inherits ToolPart
    
        ' Name of project.
        Private fieldProjectName As String = String.Empty  
    
        ' Number of tasks to display.
        Private fieldNumDisplayTasks As String = String.Empty 
    
        ' Provides unique names for the controls. 
        Private Sub UTToolPart_Init(ByVal sender As Object, _
            ByVal e As System.EventArgs)
            fieldProjectName = Me.UniqueID + "ProjectName"
            fieldNumDisplayTasks = Me.UniqueID + "NumDisplayTasks"
        End Sub
    
        Sub New()
            Me.Title = "Display Details"
            AddHandler Me.Init, AddressOf UTToolPart_Init
        End Sub
    
        ' Save the project name and number of tasks to display 
        ' in the UpcomingTasksWP class properties  
        Public Overrides Sub ApplyChanges()
            Dim upcomingTasksWebPart As UpcomingTasksWebPart = _
                CType(Me.ParentToolPane.SelectedWebPart, _
                    UpcomingTasksWebPart)
    
            upcomingTasksWebPart.ProjectName = _
                Page.Request.Form(fieldProjectName)
            upcomingTasksWebPart.NumDisplayTasks = _
                Convert.ToInt32(Page.Request.Form(fieldNumDisplayTasks))
    
            MyBase.ApplyChanges()
        End Sub
    
        ' Create the drop-down list for the project names and 
        ' the text box for the number of tasks to display.
        Protected Overrides Sub RenderToolPart( _
            ByVal textOutput As HtmlTextWriter)
    
            Dim upcomingTasksWebPart As UpcomingTasksWebPart = _
                CType(Me.ParentToolPane.SelectedWebPart, _
                    UpcomingTasksWebPart)
    
            ' Read all the project names the user has access to.
            Dim projectDS As ProjectWS.ProjectDataSet = _
                upcomingTasksWebPart.ProjectWS.ReadProjectList()
    
            textOutput.Write("<br/>")
            textOutput.Write("Project: ")
            textOutput.Write("<br/>")
            textOutput.Write("<select NAME = '" + fieldProjectName + "'>")
    
            For Each projectRow As DataRow In projectDS.Project
                If projectRow("PROJ_NAME").ToString() = _
                    upcomingTasksWebPart.ProjectName Then
    
                    textOutput.Write("<option selected VALUE='" + _
                        projectRow("PROJ_NAME") + "'>" + _
                        projectRow("PROJ_NAME"))
                Else
                    textOutput.Write("<option VALUE='" + _
                        projectRow("PROJ_NAME") + "'>" + _
                        projectRow("PROJ_NAME"))
                End If
            Next
    
            textOutput.Write("</select>")
            textOutput.Write("<br/>")
            textOutput.Write("<br/>")
            textOutput.Write("Number of Tasks to Display:")
            textOutput.Write("<br/>")
            textOutput.Write("<input type='text' name='" + _
                fieldNumDisplayTasks + "' value='" + _
                upcomingTasksWebPart.NumDisplayTasks.ToString() + "'>")
        End Sub
    End Class
    
    using System;
    using System.Web.UI;
    using System.Data;
    using Microsoft.SharePoint.WebPartPages;
    
    namespace ProjectServerWebParts
    {
        // This tool part provides the user a way to select which project's
        // tasks to display and the number of upcoming tasks to display.
        public class UTToolPart : ToolPart
        {
            private string fieldProjectName;     // Name of project.
            private string fieldNumDisplayTasks; // Number of tasks to
                                                 // display.
    
            // Provides unique names for the controls. 
            private void UTToolPart_Init(object sender, System.EventArgs e)
            {
                fieldProjectName = this.UniqueID + "ProjectName";
                fieldNumDisplayTasks = this.UniqueID + "NumDisplayTasks";
            }
    
            public UTToolPart()
            {
                this.Title = "Display Details";
                this.Init += new EventHandler(UTToolPart_Init);
            }
    
            // Save the project name and number of tasks to display 
            // in the UpcomingTasksWebPart class properties. 
            public override void ApplyChanges()
            {
                UpcomingTasksWebPart upcomingTasksWebPart =
                 (UpcomingTasksWebPart)this.ParentToolPane.SelectedWebPart;
    
                upcomingTasksWebPart.ProjectName =
                    Page.Request.Form[fieldProjectName];
                upcomingTasksWebPart.NumDisplayTasks =
                  Convert.ToInt32(Page.Request.Form[fieldNumDisplayTasks]);
    
                base.ApplyChanges();
            }
    
            // Create the drop-down list for the project names and 
            // the text box for the number of tasks to display.
            protected override void RenderToolPart(
                HtmlTextWriter textOutput)
            {
                UpcomingTasksWebPart upcomingTasksWebPart =
                 (UpcomingTasksWebPart)this.ParentToolPane.SelectedWebPart;
    
                // Read all the project names the user has access to.
                ProjectWS.ProjectDataSet projectDS = 
                    upcomingTasksWebPart.ProjectWS.ReadProjectList();
    
                textOutput.Write("<br/>");
                textOutput.Write("Project: ");
                textOutput.Write("<br/>");
                textOutput.Write("<select NAME = '" + fieldProjectName + 
                    "'>");
    
                foreach (DataRow projectRow in projectDS.Project)
                {
                    if (projectRow["PROJ_NAME"].ToString() == 
                        upcomingTasksWebPart.ProjectName)
                    {
                        textOutput.Write("<option selected VALUE='" + 
                            projectRow["PROJ_NAME"] + "'>"
                            + projectRow["PROJ_NAME"]);
                    }
                    else
                    {
                        textOutput.Write("<option VALUE='" + 
                            projectRow["PROJ_NAME"] + "'>"
                            + projectRow["PROJ_NAME"]);
                    }
                }
    
                textOutput.Write("</select>");
                textOutput.Write("<br/>");
                textOutput.Write("<br/>");
                textOutput.Write("Number of Tasks to Display:");
                textOutput.Write("<br/>");
                textOutput.Write("<input type='text' name='" + 
                    fieldNumDisplayTasks + "' value='"
                    + upcomingTasksWebPart.NumDisplayTasks + "'>");
            }
        }
    }
    

Deploying the Web Part to SharePoint Server 2007

To deploy the Upcoming Tasks Web Part to a Project Web Access server, use the following procedure.

To deploy the Upcoming Tasks Web Part

  1. Copy the Upcoming Tasks Web Part assembly to the target computer by doing the following:

    1. Copy the compiled assembly (ProjectServerWebParts.dll) to any convenient folder on the target computer.

    2. Open the global assembly cache on the Project Web Access server. On the Start menu, click Run, and then type assembly.

    3. Drag the ProjectServerWebParts.dll file from the temporary folder to the global assembly cache window.

    4. Right-click the assembly file in the global assembly cache window, click Properties, double-click the value of the Public Key Token, and then copy it to the Clipboard.

  2. Register the Upcoming Tasks Web Part as a safe control. Open the web.config file for the Project Web Access site where you want to add the Web Part. There are typically several Web sites on a server, and there can also be several Project Web Access sites. To find the correct Web.config file, do the following:

    1. In Internet Information Services (IIS) Manager, expand the Web Sites node, right-click the Project Web Access site you want, and then click Properties. In many cases, Project Web Access is in the Default Web Site.

    2. In the Web Site Properties dialog box, click the Home Directory tab. The web.config file in the directory specified in the Local path box is the file to modify.

    Add the following <SafeControl/> tag to the <SafeControls></SafeControls> section of the web.config file.

    <SafeControl Assembly="ProjectServerWebParts, Version=1.0.0.0,
      Culture=neutral, PublicKeyToken=[PKToken]"
      Namespace=" ProjectServerWebParts" 
      TypeName="*" Safe="True" />
    

    Replace the [PKToken] placeholder shown earlier for the PublicKeyToken value with the public key token copied in Step 1.

  3. Restart IIS. In a Command Prompt window on the server, type iisreset.

  4. Create a Web Part definition file for the Upcoming Tasks Web Part:

    1. Open a new file in a text editor such as Notepad, and add the following XML code to the file.

      <?xml version="1.0"?>
      <WebPart xmlns="http://schemas.microsoft.com/WebPart/v2">
         <Assembly>ProjectServerWebParts, Version=1.0.0.0, Culture=Neutral,
           PublicKeyToken=[PKToken]</Assembly>
         <TypeName>ProjectServerWebParts.UpcomingTasksWebPart</TypeName>
         <Title>Upcoming Tasks Web Part</Title>
         <Description>Shows upcoming tasks for a project.</Description>
      </WebPart>
      
    2. Replace the [PKToken] placeholder shown earlier for the PublicKeyToken value with the public key token copied previously in Step 1.

    3. Save the file as UpcomingTasksWebPart.dwp to a folder where it is accessible from Office SharePoint Server.

  5. Add the Upcoming Tasks Web Part to the Web Part gallery:

    1. Open Project Web Access, and on the Site Actions menu, click Site Settings.

    2. On the Site Settings page, in the Galleries section, click Web Parts.

    3. On the Web Part Gallery page, click Upload.

    4. On the Upload Web Part: Web Part Gallery page, browse to the UpcomingTasksWebPart.dwp file you created previously. Select Overwrite existing file(s), and then click OK.

      The UpcomingTasksWebPart.dwp file provisions the Web Part Gallery: UpcomingTasksWebPart page.

      Figure 3. Adding Web Part to Web Part gallery

      Adding Web Part to Web Part gallery

    5. In the Group section, select Default Web Parts in the drop-down list.

    6. To include the Upcoming Tasks Web Part in the Quick Add Groups list, click Default. To leave the custom Web Part out of the list, clear both check boxes, and then click OK.

  6. After you deploy the Upcoming Tasks Web Part to the Project Web Access server, test it by doing the following:

    1. Open Project Web Access in the browser and navigate to the Project Web Access home page.

    2. Click the Site Actions menu, and then click Edit Page.

    3. Click Add a Web Part in the Footer Web Part zone.

    4. In the Add Web Parts to footer dialog box, locate the Default Web Parts category and select the Upcoming Tasks Web Part.

      Figure 4. Adding Web Part

      Adding Web Part

    5. Click Add to add the Web Part to the zone. The Upcoming Tasks Web Part is displayed, showing the default configuration directions.

      Figure 5. Default configuration directions

      Default configuration directions

    6. In the Web Part menu, click Modify Shared Web Part to display the tool pane.

    7. In the Appearance, Layout, and Advanced sections of the Upcoming Tasks tool pane, make any changes you want.

    8. Expand the Display Details section of the tool pane, and then select the project and number of tasks to display.

    9. Click Apply to apply the changes. The Upcoming Tasks Web Part displays the open tasks for the selected project.

      Figure 6. Displaying open tasks

      Displaying open tasks

    Note

    You might need to stop and then start IIS on the Project Web Access computer before you can add the Upcoming Tasks Web Part to a zone.

Read It

This article explores creating a custom Web Part for Project Server 2007. The key steps are:

  1. Creating a Web Control Library project in Visual Studio 2005.

  2. Adding the required references.

  3. Setting the Web Part assembly version number.

  4. Signing the Web Part assembly with a strong name.

  5. Adding the code that implements the functionality of the Web Part that displays the upcoming tasks for a specified project.

  6. Deploying the Web Part.

Explore It