Using Visual Web Parts vs. Traditional Web Parts in SharePoint 2010

Summary:  Learn about the advantages of using Visual Web Parts and traditional Web Parts in SharePoint 2010.

Applies to: Business Connectivity Services | Open XML | SharePoint Designer 2010 | SharePoint Foundation 2010 | SharePoint Online | SharePoint Server 2010 | Visual Studio

Provided by:  Prasadarao Vithanala, Microsoft Corporation

Contents

  • Introduction to Visual Web Part Issues

  • Differences between a Web User Control and a Web Part

  • Differences between Visual Web Parts and Code-Only Web Parts

  • Creating a Code-Only Web Part and a Visual Web Part

  • Conclusion

  • Additional Resources

Introduction to Visual Web Part Issues

In Microsoft Office SharePoint Server 2007, developers create Web Parts by deriving from the WebPart class. One of the challenges that you face when designing a Web Part that has a complex user interface (UI) is the lack of drag-and-drop support. You must write the code from scratch, in the CreateChildControls method, to create the layout design of the Web Part, which can be time consuming.

An alternative approach can save development time:

  1. Create a web user control by using Microsoft Visual Studio 2010 and design the control with the Visual Web Developer designer.

  2. Write the code-behind implementation of the user control.

  3. Create a Web Part to host the web user control.

Visual Web Developer provides drag-and-drop support without the need to write supporting code.

Differences between a Web User Control and a Web Part

When making the decision on whether to use a user control or Web Part to retrieve and display content on a SharePoint portal, you should understand the advantages and disadvantages of each approach.

User Control

Web Part

User controls are based on Microsoft ASP.NET, and most developers are familiar with developing user controls. This improves productivity.

In general, developers are not familiar with creating child controls by writing the code from scratch.

User controls can be used with ASP.NET -based solutions. If you decide later to convert a project containing a user control to an ASP.NET -based solution, you should be able to use the control without making any changes.

Web Parts can be used in ASP.NET -based solutions only when the solution uses Web Parts pages.

The Visual Web Developer designer provides support for designing the UI by using drag-and-drop operations that gives the control a consistent look-and-feel, which results in faster development.

The controls in Web Parts must be added by using code.

User controls must be compiled before use, which adds to the time it takes to load the control.

Web Parts are precompiled and ready for use as soon as you need them.

Differences between Visual Web Parts and Code-Only Web Parts

Microsoft SharePoint 2010 introduced Visual Web Parts. Visual Web Parts are similar to user controls in that you can simply drag and drop items from the Toolbox onto your custom controls to create a Web Part UI. You also get the code-behind file where you implement the UI logic. Technically, the SharePoint 2010 Visual Web Part is an ASCX web user control that is hosted inside a standard Web Part.

A Visual Web Part is simply a classic Web Part that automatically loads the web user control with it. The advantage of this approach is that you can use Visual Web Developer to design the web user control. Traditional Web Parts differ from Visual Web Parts in several ways.

Differences in Web Part Properties

Adding Web Part properties is cumbersome for Visual Web Parts as compared to traditional Web Parts. As you develop Web Parts, many times you will want to expose their properties so that users and administrators can supply the values for those properties.

Traditional Web Part

When you create a new Web Part (in this case SimpleWebPart), the SimpleWebPart.cs file is created for you. This is where you define the Web Part properties that inherit from the WebPart class. The following code snippet defines a Web Part property, named MyProperty, to display to a user.

public static string myprop;

    [WebBrowsable(true),
    Category("Configuration"),
    Personalizable(PersonalizationScope.Shared),
    DefaultValue(""),
    WebDisplayName("Property Title"),
    WebDescription("Property Description")]
    public string MyProperty
    {
        get { return myprop; }
        set { myprop = value; }
    }

Visual Web Part

When you create a new Visual Web Part, (for example, SimpleVisualWebPart), the following files are created for you:

  • SimpleVisualWebPart.cs

  • SimpleVisualWebPartUserControl.ascx

  • SimpleVisualWebPartUserControl.ascx.cs

These files contain the logic for the Web Part that is defined in the SimpleVisualWebPart object.

To define a custom property in a Visual Web Part

  1. In the code-behind file for your user control (in this example, SimpleVisualWebPartUserControl.ascx.cs), declare a property.

    public SimpleVisualWebPart WebPart { get; set; }
    
  2. In the SimpleVisualWebPart.cs file, define the property as follows.

    [Personalizable(),
        WebBrowsable, 
        DefaultValue("Tasks"), 
        DisplayName("Name of the Tasks List"),
        Category("Task WebPart Settings")]
        public string ListName { get; set; }
    protected override void CreateChildControls()
    {
        SimpleVisualWebPartUserControl control = 
            Page.LoadControl(_ascxPath) as SimpleVisualWebPartUserControl;
        if (control != null)
        {
            control.WebPart = this;
        }
            Controls.Add(control);
    }
    
  3. You can now use the property in the code for your user control.

    if (this.WebPart != null && 
        this.WebPart.ListName != null && 
        this.WebPart.ListName.Length > 0)
    {
        TextBox1.Text = web.Lists.TryGetList(this.WebPart.ListName);
    }
    

Differences in Sandboxed Solutions

Sandboxed solutions, a feature in SharePoint 2010, can be deployed by site collection administrators (or any user with appropriate permissions) and enable site administrators to deploy WSP packages, allocate resource quotas, and monitor the resource usage of sandboxed solutions. Sandboxed solutions have access to only a subset of objects in the SharePoint object model. Because they run in isolation, they do not pose a threat to the farm in cases of malicious software.

Farm solutions, though, can be deployed only by farm site administrators and require full trust that allows unrestricted access to the entire SharePoint object model. Visual Web Parts can be deployed only as farm solutions because they deploy the user controls to the SharePoint root folder. Traditional Web Parts can be deployed as sandboxed solutions. Consider the case in which you create a Web Part that contains an indefinite loop, and you deploy that as sandboxed solution. Because it is a sandboxed solution, the code does not put your SharePoint farm in danger. Instead, it displays a message similar to the one shown in Figure 1.

Figure 1. Web Part error

Web Part error

The Microsoft Visual Studio team has released the Visual Studio 2010 SharePoint Power Tools. These tools extend the existing SharePoint 2010 project templates and provide the Sandboxed Visual Web Part template that enables you to create Web Parts that can be deployed as sandboxed solutions. The use of these templates also enables designer support for designing the Web Parts.

Differences in Web Part Connections

Web Part connections are interfaces that define the communications between a Web Part provider and a Web Part consumer. The provider Web Part exposes data to an interface that you specify, which can then be used to consume the data in the consumer Web Part. This is easily achieved in a traditional Web Part because the logic code is contained in the Web Part itself.

In a Visual Web Part, the Web Part loads the user control, which contains the control logic. This can be implemented by using an approach similar to that of implementing Visual Web Part properties described in the previous section. The following steps demonstrate specifying Visual Web Part connections.

To set up Visual Web Part connections

  1. Create the interface to provide and consume the data.

    public interface IProvideMyName { int Name { get; } }
    
  2. Create the provider Web Part and specify its connections as follows.

    [ConnectionProvider("Name")]
        IProvideMyName Name()
        {
            return this;
        }
        int IProvideMyName.Name
        {
            get
            {
                return "Provider Web Part";
            }
         }
    
  3. Create the consumer Web Part to consume the data from the provider.

    public class ConsumerWebPart : WebPart
        {
            private const string _ascxPath = 
                @"~/_CONTROLTEMPLATES/WebPartConnections/MyConsumer/ConsumerWebPartUserControl.ascx";
            protected override void CreateChildControls() 
            { 
                ConsumerWebPartUserControl control = 
                    Page.LoadControl(_ascxPath) as ConsumerWebPartUserControl;
    
                // Assign the current Web Part instance to the property of user control.
                control.WebPart = this; 
                Controls.Add(control);
            } 
    
            public int Name { get; set; }
            [ConnectionConsumer("Name")]
            public void SetName(IProvideMyName provider)
            { 
                if (provider != null) 
                {
                    this.Name = provider.Name;
                } 
            }
        }
    
        public partial class ConsumerWebPartUserControl : UserControl
        {
            public ConsumerWebPart WebPart { get; set; }
            protected override void OnPreRender(EventArgs e)
            {
                base.OnPreRender(e);
                this.Label1.Text = this.WebPart.Name.ToString();
            }
        }
    
  4. Add the Web Parts to the Web Parts page and connect them by using the provider name.

Differences when Extending a Web Part

You can extend the traditional Web Part by inheriting from the WebPart class. You can then reuse the base Web Part functionality and extend it as desired. Visual Web Parts cannot be extended. Because this Web Part is a wrapper around a user control, it just contains the code to load the user control; the bulk of the Web Part code resides in the code-behind file of the user control.

Differences in Performance and Memory Footprint

Visual Web Parts have slightly larger memory footprints than code-only Web Parts. Visual Web Parts contain more parts (Web Part, user control) than traditional Web Parts. Thus, loading a Visual Web Part takes longer than a traditional Web Part, resulting in poorer performance. Additionally, creating a Visual Web Part by using the Visual Web Developer designer may add more controls and objects than manually building the control hierarchy in the code in a traditional Web Part. This also has the potential to increase the memory footprint of a Visual Web Part.

Creating a Code-Only Web Part and a Visual Web Part

In this section, you see an example of developing both a code-only Web Part and a Visual Web Part to see the differences in implementing both approaches. The samples need to do the following:

  1. Create a Web Part that displays the contents of any SharePoint tasks list with specific conditions.

  2. Create two custom properties with the following conditions:

    • ListName property: If the list name is provided, read the records from that task list; if nothing is specified, read the records from the default tasks list.

    • AssignedTo property: If this property is specified, filter out the records with the given value; otherwise, filter the records with the currently logged-in user.

To create the code-only Web Part

  1. In Visual Studio 2010, create a new project by clicking New Project, SharePoint, 2010, and then selecting Visual Web Part, as shown in Figure 2.

    Figure 2. Select a Visual Web Part template

    Select a Visual Web Part template

  2. Name the project SPVisualWebParts, and then click OK.

  3. The SharePoint Customization Wizard is displayed as shown in Figure 3. Specify the desired target site (in this case, https://localhost:38914), select Deploy as a farm solution, and then click Finish.

    Figure 3. SharePoint Customization Wizard screen

    SharePoint Customization Wizard screen

  4. Visual Studio 2010 creates the project. It automatically adds packaging and feature settings and a sample Visual Web Part. Delete the VisualWebPart1 file from Solution Explorer.

  5. In Solution Explorer, right-click SPVisualWebParts, click Add, click New Item, and then select Web Part. Name the Web Part TasksCustomWebPart, and then click Add (see Figure 4).

    Figure 4. Add a Web Part

    Add a Web Part

    Figure 5 shows what you should see in Solution Explorer.

    Figure 5. Files in Solution Explorer

    Files in Solution Explorer

    The project structure contains following items:

    • The Package folder specifies all settings that are required for a SharePoint 2010 solution. You can also configure some important settings like selecting which features you want to package.

    • The Features folder contains one or more feature definitions.

    • The TasksCustomWebPart folder contains the following files:

      • TasksCustomWebPart.webpart contains the Web Part default properties, such as Title and Description. It also contains metadata information such as the type and assembly that contains this Web Part.

      • Elements.xml contains settings for deploying the TasksCustomWebPart.webpart file into the URL _catalogs/wp.

      • TasksCustomWebPart.cs contains the actual implementation logic for the Web Part. This Web Part implements the class System.UI.WebControls.WebPart.

  6. Add the following code to the TasksCustomWebPart.cs file.

    /// Code of TasksCustomWebPart.cs file
    
    using System;
    using System.ComponentModel;
    using System.Drawing;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebControls;
    using System.Collections.Generic;
    using System.Text;
    
    namespace SPVisualWebParts.TasksCustomWebPart
    {
        /// <summary>
        /// TaskEntity that contains the properties for task list fields.
        /// </summary>
        public class TaskEntity
        {
            private string assignedTo;
    
            public string Title { get; set; }
            public string AssignedTo
            {
                get
                {
                    if (assignedTo.Length > 0)
                    {
                        string[] user =
                            assignedTo.Split(
                            SPFieldMultiChoiceValue.Delimiter.ToCharArray());
                        return user[user.Length - 1];
                    }
    
                    return string.Empty;
                }
                set { assignedTo = value; }
            }
            public string Description { get; set; }
            public string Status { get; set; }
            public string Priority { get; set; }
            public DateTime StartDate { get; set; }
            public DateTime DueDate { get; set; }
            public string href { get; set; }
    
        }
    
        /// <summary>
        /// Implementation of TasksCustomWebPart class.
        /// </summary>
        [ToolboxItemAttribute(false)]
        public class TasksCustomWebPart : WebPart
        {
            /// <summary>
            /// Assigned To property comes in custom properties of Web Part tool part.
            /// If the value is specified, the Web Part displays records filtered by that user.
            /// </summary>
            [Personalizable(), WebBrowsable, Category("Task WebPart Settings")]
            public string AssignedTo { get; set; }
    
            /// <summary>
            /// List Name property allows Web Part user to specify which tasks list to use to retrieve data.
            /// If nothing is specified, it takes Tasks as List Name.
            /// </summary>
            [Personalizable(),
            WebBrowsable,
            DefaultValue("Tasks"),
            Category("Task WebPart Settings")]
            public string ListName { get; set; }
    
            /// <summary>
            /// Grid view to display task results.
            /// </summary>
            private GridView gridViewTasks = default(GridView);
    
            protected override void CreateChildControls()
            {
                base.CreateChildControls();
    
                this.gridViewTasks = new GridView();
                this.gridViewTasks.ID = "GridViewTasks";
                this.gridViewTasks.AutoGenerateColumns = false;
                this.gridViewTasks.BackColor = 
                    System.Drawing.ColorTranslator.FromHtml("#DEBA84");
                this.gridViewTasks.BorderColor = 
                    System.Drawing.ColorTranslator.FromHtml("#DEBA84");
                this.gridViewTasks.BorderStyle = BorderStyle.None;
                this.gridViewTasks.BorderWidth = new Unit("1px");
                this.gridViewTasks.CellPadding = 3;
                this.gridViewTasks.CellSpacing = 2;
                this.gridViewTasks.EnableModelValidation = true;
    
                this.gridViewTasks.FooterStyle.BackColor = 
                    System.Drawing.ColorTranslator.FromHtml("#F7DFB5");
                this.gridViewTasks.FooterStyle.ForeColor = 
                    System.Drawing.ColorTranslator.FromHtml("#8C4510");
    
                this.gridViewTasks.HeaderStyle.BackColor =
                    System.Drawing.ColorTranslator.FromHtml("#A55129");
                this.gridViewTasks.HeaderStyle.Font.Bold = true;
                this.gridViewTasks.HeaderStyle.ForeColor = Color.White;
    
                this.gridViewTasks.PagerStyle.ForeColor =
                    System.Drawing.ColorTranslator.FromHtml("#8C4510");
                this.gridViewTasks.PagerStyle.HorizontalAlign = HorizontalAlign.Center;
    
                this.gridViewTasks.RowStyle.BackColor =
                    System.Drawing.ColorTranslator.FromHtml("#FFF7E7");
                this.gridViewTasks.RowStyle.ForeColor =
                    System.Drawing.ColorTranslator.FromHtml("#8C4510");
    
                this.gridViewTasks.SelectedRowStyle.BackColor =
                    System.Drawing.ColorTranslator.FromHtml("#738A9C");
                this.gridViewTasks.SelectedRowStyle.ForeColor = Color.White;
                this.gridViewTasks.SelectedRowStyle.Font.Bold = true;
    
                HyperLinkField title = new HyperLinkField();
                title.DataTextField = "Title";
                title.HeaderText = "Title";
                title.DatahrefFields = new string[] { "href"};
                this.gridViewTasks.Columns.Add(title);
    
    
                BoundField assignedTo = new BoundField();
                assignedTo.DataField = "AssignedTo";
                assignedTo.HeaderText = "Assigned To";
                this.gridViewTasks.Columns.Add(assignedTo);
    
    
                BoundField description = new BoundField();
                description.DataField = "Description";
                description.HeaderText = "Description";
                this.gridViewTasks.Columns.Add(description);
    
                BoundField status = new BoundField();
                status.DataField = "Status";
                status.HeaderText = "Status";
                this.gridViewTasks.Columns.Add(status);
    
                BoundField priority = new BoundField();
                priority.DataField = "Priority";
                priority.HeaderText = "Priority";
                this.gridViewTasks.Columns.Add(priority);
    
                BoundField startDate = new BoundField();
                startDate.DataField = "StartDate";
                startDate.HeaderText = "Start Date";
                startDate.DataFormatString = "{0:MMMM d, yyyy}";
                this.gridViewTasks.Columns.Add(startDate);
    
                BoundField dueDate = new BoundField();
                dueDate.DataField = "DueDate";
                dueDate.HeaderText = "Due Date";
                dueDate.DataFormatString = "{0:MMMM d, yyyy}";
                this.gridViewTasks.Columns.Add(dueDate);
    
                this.Controls.Add(this.gridViewTasks);
    
            }
    
            /// <param name="e"></param>
            protected override void OnLoad(EventArgs e)
            {
                base.OnLoad(e);
    
                EnsureChildControls();
    
                SPWeb web = SPContext.Current.Web;
                SPList list = default(SPList);
    
                // If ListName Web Part property is specified, use it. Use Tasks otherwise.
                if (this.ListName != null &&
                    this.ListName.Length > 0)
                {
                    list = web.Lists.TryGetList(this.ListName);
                }
                else
                {
                    list = web.Lists.TryGetList("Tasks");
                }
    
                this.gridViewTasks.DataSource = this.GetTasksEntity(list);
                this.gridViewTasks.DataBind();
            }
    
            /// <summary>
            /// Return the TaskEntity list with filtered results. 
            /// </summary>
            /// <param name="list">return the list of tasks.</param>
            /// <returns></returns>
            private List<TaskEntity> GetTasksEntity(SPList list)
            {
                List<TaskEntity> tasks = new List<TaskEntity>();
    
                StringBuilder sb = new StringBuilder();
                sb.Append("<Where>");
                sb.Append("     <Eq>");
                sb.Append("        <FieldRef Name='AssignedTo' />");
    
                // If AssignedTo Web Part property is specified, use it. Use current logged-in user otherwise.
                if (this.AssignedTo != null &&
                    this.AssignedTo.Length > 0)
                {
                    sb.Append(string.Format(
                        "        <Value Type='User'>{0}</Value>", this.AssignedTo));
                }
                else
                {
                    sb.Append(string.Format(
                        "        <Value Type='User'>{0}</Value>", SPContext.Current.Web.CurrentUser.Name));
                }
    
                sb.Append("     </Eq>");
                sb.Append("</Where>");
    
                SPQuery query = new SPQuery();
                query.Query = sb.ToString();
    
                SPListItemCollection items = list.GetItems(query);
    
                if (list != null && list.Items.Count > 0)
                {
                    foreach (SPListItem item in items)
                    {
                        TaskEntity task = new TaskEntity();
    
                        task.Title = this.GetFieldValue(item, "Title");
                        task.href = string.Concat(
                            list.DefaultDisplayFormUrl,
                            string.Format("?ID={0}", item.ID));
                        task.Description = this.GetFieldValue(item, "Description");
                        task.AssignedTo = this.GetFieldValue(item, "AssignedTo");
                        task.Status = this.GetFieldValue(item, "Status");
                        task.Priority = this.GetFieldValue(item, "Priority");
                        task.StartDate = DateTime.Parse(item["StartDate"].ToString());
                        task.DueDate = DateTime.Parse(item["DueDate"].ToString());
    
                        tasks.Add(task);
                    }
                }
    
                return tasks;
            }
    
            /// <summary>
            /// Get the item field value. Also, check if the field is available before accessing.
            /// </summary>
            /// <param name="item"></param>
            /// <param name="fieldName"></param>
            /// <returns></returns>
            private string GetFieldValue(SPListItem item, string fieldName)
            {
                string strFieldValue = string.Empty;
    
                if (item != null && item.Fields.ContainsField(fieldName) && item[fieldName] != null)
                {
                    strFieldValue = item[fieldName].ToString();
                }
    
                return strFieldValue;
            }
        }
    }
    

    Because this is an example of a code-only Web Part, it doesn't have the Visual Studio 2010 designer capabilities to design the controls. All controls are created in the code itself. The code contains the following methods:

    • CreateChildControls   The code overrides this method and adds all of the controls to show in the UI. This example demonstrates that the entire design of a grid view is done with coding. All header styles, footer styles, and other settings are coded in this method.

    • OnLoad   The code overrides this method to retrieve data from any data source and then bind the data to the UI controls. It calls EnsureChildControls to wait until the CreateChildControls method execution finishes. The Web Part retrieves data from the Tasks list data source and binds the data to the grid view. To bind the retrieved data to the UI control during the postback button-click event, bind the data in the OnPreRender method because the button-click event handler might change the data in the data source.

  7. To deploy the solution, in Solution Explorer, right-click SPVisualWebParts and then click Deploy. Visual Studio 2010 builds the solution package and deploys the solution (as shown in Figure 6).

    Figure 6. Deploy the Web Part

    Deploy the Web Part

  8. In the SharePoint site where the solution is deployed, click Site Actions and then click View All Site Content, as shown in Figure 7.

    Figure 7. Navigate to View All Site Content

    Navigate to View All Site Content

  9. Click Create. In the Create page. click Page and then click Web Part Page (see Figure 8) to create a new Web Parts page.

    Figure 8. Create a new Web Part page

    Create a new Web Part Page

  10. When the Web Parts page is created, it is shown in edit mode. Click Add Web Part. In the Categories list, select Custom. In the Web Parts list, select TasksCustomWebPart (see Figure 9) and click Add.

    Figure 9. Add TasksCustomWebPart Web Part to the page

    Add TasksCustomWebPart Web Part to the Page

  11. Now the Web Parts page should resemble Figure 10.

    Figure 10. Add the Web Part to the page

    Add the Web Part to the page

  12. Navigate to the Web Parts page and click Edit Web Part, as shown in Figure 11, to change the properties of the Web Part.

    Figure 11. Location of Edit Web Part menu item

    Select Edit Web Part menu

  13. Change the AssignedTo property to Sriram Sundaresan and the ListName property to Tasks, as shown in Figure 12.

    Figure 12. Set the custom properties

    Set the custom properties

    The updated results resemble to Figure 13.

    Figure 13. Updated page

    Updated page

To create a Visual Web Part

  1. Use same project (SPVisualWebParts) for the code-only Web Part. In Solution Explorer, right-click, click Add, and then click New Item. In the Add New Item window, select the Visual Web Part item template in the SharePoint 2010 group; by default, Visual Web Part is selected. Name the new Web Part TasksVisualWebPart (as shown in Figure 14) and then click Add.

    Figure 14. Add a new Visual Web Part

    Add a new Visual Web Part

    Solution Explorer should resemble to Figure 15.

    Figure 15. Updated project

    Updated project

    A folder (named TasksVisualWebPart) for the new Web Part now contains all the necessary supporting files.

    • TasksVisualWebPart.webpart   Contains the Web Part default properties such as Title and Description. It also contains metadata information such as the type of the Web Part and the name of the assembly that contains the Web Part.

    • Elements.xml   Contains the settings for deploying the TasksVisualWebPart.webpart file into the URL _catalogs/wp.

    • TasksVisualWebPart.cs   Contains the logic to load the user control inside the Web Part. This Web Part implements the class System.UI.WebControls.WebPart.

    • TasksVisualWebPartUserControl.ascx   The web user control used to design the UI by using Visual Studio support.

    • TasksVisualWebPartUserControl.ascx.cs   The code-behind file for the web user control. It contains the logic that retrieves the data and binds the results to the UI controls.

    • TasksVisualWebPart.cs    Contains the following code.

      using System;
      using System.ComponentModel;
      using System.Web;
      using System.Web.UI;
      using System.Web.UI.WebControls;
      using System.Web.UI.WebControls.WebParts;
      using Microsoft.SharePoint;
      using Microsoft.SharePoint.WebControls;
      
      namespace SPVisualWebParts.TasksVisualWebPart
      {
          [ToolboxItemAttribute(false)]
          public class TasksVisualWebPart : WebPart
          {
              // Visual Studio might automatically update this path
              // when you change the Visual Web Part project item.
              private const string _ascxPath = 
                @"~/_CONTROLTEMPLATES/SPVisualWebParts/TasksVisualWebPart/TasksVisualWebPartUserControl.ascx";
      
              protected override void CreateChildControls()
              {
                  TasksVisualWebPartUserControl control = 
                    Page.LoadControl(_ascxPath) as TasksVisualWebPartUserControl;
                  if (control != null)
                  {
                      control.WebPart = this;
                  }
                  Controls.Add(control);
              }
      
              [Personalizable(), WebBrowsable, Category("Task WebPart Settings")]
              public string AssignedTo { get; set; }
      
              [Personalizable(),
              WebBrowsable, 
              DefaultValue("Tasks"), 
              Category("Task WebPart Settings")]
              public string ListName { get; set; }
      
          }
      }
      

      This code does the following:

      1. A private member, _ascxPath, is declared and is then initialized with the path of the web user control.

      2. In the CreateChildControls method, the web user control is loaded by using Page.LoadControl method. The loaded control is added to the control collection.

      The Web user control does not have an option to define the custom properties. You have to create properties inside the Web Part and make these properties available to the user control. Create two custom properties for the Web Part named AssignedTo and ListName.

    • TasksVisualWebPartUserControl.ascx    Contains the following code.

      <%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
      <%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, 
          PublicKeyToken=71e9bce111e9429c" %> 
      <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" 
          Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, 
          PublicKeyToken=71e9bce111e9429c" %> 
      <%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" 
          Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, 
          PublicKeyToken=71e9bce111e9429c" %>
      <%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, 
          Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
      <%@ Import Namespace="Microsoft.SharePoint" %> 
      <%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" 
          Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
      <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="TasksVisualWebPartUserControl.ascx.cs" 
          Inherits="SPVisualWebParts.TasksVisualWebPart.TasksVisualWebPartUserControl" %>
      
      <asp:GridView ID="GridViewTasks" runat="server" AutoGenerateColumns="False" 
          BackColor="#DEBA84" BorderColor="#DEBA84" BorderStyle="None" BorderWidth="1px" 
          CellPadding="3" CellSpacing="2" EnableModelValidation="True">
          <Columns>
              <asp:HyperLinkField DataTextField="Title" HeaderText="Title" 
                  DatahrefFields="href" />
              <asp:BoundField DataField="AssignedTo" HeaderText="Assigned To" />
              <asp:BoundField DataField="Description" HeaderText="Description" />
              <asp:BoundField DataField="Status" HeaderText="Status" />
              <asp:BoundField DataField="Priority" HeaderText="Priority" />
              <asp:BoundField DataField="StartDate" DataFormatString="{0:MMMM d, yyyy}" 
                  HeaderText="Start Date" />
              <asp:BoundField DataField="DueDate" HeaderText="Due Date" 
                  DataFormatString="{0:MMMM d, yyyy}" />
          </Columns>
          <FooterStyle BackColor="#F7DFB5" ForeColor="#8C4510" />
          <HeaderStyle BackColor="#A55129" Font-Bold="True" ForeColor="White" />
          <PagerStyle ForeColor="#8C4510" HorizontalAlign="Center" />
          <RowStyle BackColor="#FFF7E7" ForeColor="#8C4510" />
          <SelectedRowStyle BackColor="#738A9C" Font-Bold="True" ForeColor="White" />
      </asp:GridView>
      
  2. Drag the grid view control from the Toolbox to the Visual Studio designer, as shown in Figure 16.

    Figure 16. Drag the grid view control to the design surface

    Drag the grid view control to the design surface

    For a code-only Web Part, you create the entire grid view and its styles and columns through .NET Framework coding by using the CreateChildControls method. But in the Visual Web Part, you design it by using the Visual Studio designer.

    The following code snippet shows the code-behind for the web user control (TasksVisualWebPartUserControl.ascx.cs).

    using System;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using Microsoft.SharePoint;
    using System.Collections.Generic;
    using System.Text;
    
    namespace SPVisualWebParts.TasksVisualWebPart
    {
        /// <summary>
        /// Code-behind file for the web user control.
        /// </summary>
        public partial class TasksVisualWebPartUserControl : UserControl
        {
            /// <summary>
            /// The web user control code-behind cannot access the Web Part 
            /// custom properties directly. So, TasksVisualWebPart is declared
            /// and the instance is assigned in CreateChildControls() of 
            /// the TasksVisualWebPart.cs file. The web user control can 
            /// access custom properties by using this property.
            /// 
            /// </summary>
            public TasksVisualWebPart WebPart { get; set; }
    
            /// <summary>
            /// If you don't have any dependency on the custom properties in the 
            /// Page_Load() event, you can bind the data to the grid view inside 
            /// this event.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            protected void Page_Load(object sender, EventArgs e)
            {
    
            }
    
            /// <summary>
            /// In the code-only Web Part, you can bind the data to the grid 
            /// view in the OnLoad event or OnPreRender event. In the web user 
            /// control code-behind, you cannot bind the data in Page_Load 
            /// method. Whenever the following code is executed--
            /// 
            ///  TasksVisualWebPartUserControl control = Page.LoadControl(_ascxPath) 
            ///     as TasksVisualWebPartUserControl;
            ///  Controls.Add(control);
    
            ///
            /// --it automatically starts the life cycle of user control. It then calls 
            /// Page_Load() method before executing the below code. The following code 
            /// sets the TasksVisualWebPart Web Part instance to web user control
            /// Web Part property.
            /// 
            ///     if (control != null)
            ///     {
            ///          control.WebPart = this;
            ///     }
            /// 
            /// </summary>
            /// <param name="e"></param>
            protected override void OnPreRender(EventArgs e)
            {
                base.OnPreRender(e);
    
                SPWeb web = SPContext.Current.Web;
                SPList list = default(SPList);
    
                if (this.WebPart != null && 
                    this.WebPart.ListName != null && 
                    this.WebPart.ListName.Length > 0)
                {
                    list = web.Lists.TryGetList(this.WebPart.ListName);
                }
                else
                {
                    list = web.Lists.TryGetList("Tasks");
                }
    
                this.GridViewTasks.DataSource = this.GetTasksEntity(list);
                this.GridViewTasks.DataBind();
            }
    
            /// <summary>
            /// Get the TaskEntity entity.
            /// </summary>
            /// <param name="list"></param>
            /// <returns></returns>
            private List<TaskEntity> GetTasksEntity(SPList list)
            {
                List<TaskEntity> tasks = new List<TaskEntity>();
    
                StringBuilder sb = new StringBuilder();
                sb.Append("<Where>");
                sb.Append("     <Eq>");
                sb.Append("        <FieldRef Name='AssignedTo' />");
    
                if (this.WebPart != null && 
                    this.WebPart.AssignedTo != null && 
                    this.WebPart.AssignedTo.Length > 0)
                {
                    sb.Append(string.Format("        <Value Type='User'>{0}</Value>", 
                        this.WebPart.AssignedTo));
                }
                else
                {
                    sb.Append(string.Format("        <Value Type='User'>{0}</Value>", 
                        SPContext.Current.Web.CurrentUser.Name));
                }
    
                sb.Append("     </Eq>");
                sb.Append("</Where>");
    
                SPQuery query = new SPQuery();
                query.Query = sb.ToString();
    
                SPListItemCollection items = list.GetItems(query);
    
                if (list != null && list.Items.Count > 0)
                {
                    foreach (SPListItem item in items)
                    {
                        TaskEntity task = new TaskEntity();
    
                        task.Title = this.GetFieldValue(item, "Title");
                        task.href = string.Concat(
                            list.DefaultDisplayFormUrl, 
                            string.Format("?ID={0}", item.ID));
                        task.Description = this.GetFieldValue(item,"Description");
                        task.AssignedTo = this.GetFieldValue(item,"AssignedTo");
                        task.Status = this.GetFieldValue(item,"Status");
                        task.Priority =  this.GetFieldValue(item,"Priority");
                        task.StartDate = DateTime.Parse(item["StartDate"].ToString());
                        task.DueDate = DateTime.Parse(item["DueDate"].ToString());
    
                        tasks.Add(task);
                    }
    
                }
    
                return tasks;
            }
    
            private string GetFieldValue(SPListItem item, string fieldName)
            {
                string strFieldValue = string.Empty;
    
                if (item != null && item.Fields.ContainsField(fieldName) && item[fieldName] != null)
                {
                    strFieldValue = item[fieldName].ToString();
                }
    
                return strFieldValue;
            }        
        }
    
        /// <summary>
        /// Task entity for the Tasks list.
        /// </summary>
        public class TaskEntity
        {
            private string assignedTo;
    
            public string Title { get; set; }
            public string AssignedTo
            {
                get
                {
                    if (assignedTo.Length > 0)
                    {
                        string[] user =
                            assignedTo.Split(
                            SPFieldMultiChoiceValue.Delimiter.ToCharArray());
                        return user[user.Length - 1];
                    }
    
                    return string.Empty;
                }
                set { assignedTo = value; }
            }
            public string Description { get; set; }
            public string Status { get; set; }
            public string Priority { get; set; }
            public DateTime StartDate { get; set; }
            public DateTime DueDate { get; set; }
            public string href { get; set; }
    
        }
    }
    

    In this code, the first statement inside the TasksVisualWebPartUserControl class declares a member of type TasksVisualWebPart that points to the instance of a Web Part that loads this user control. Because the web user control cannot access the custom properties of Web Part directly, it uses this member to access all of the custom properties that are defined for the Web Part.

    In the case of the code-only Web Part, you can bind the data in OnLoad method as shown in the earlier example. You can do so because you can access custom properties inside the Web Part, and you can block the thread to wait until the CreateChildControls method finishes by using EnsureChildControls. However, the Visual Web Part is different when compared to the code-only Web Part: You can access custom properties by using the property (TasksVisualWebPart WebPart) that you declared in the previous step. In the Page_Load event of the web user control, the custom properties have null values because the life cycle of the web user control begins when the ASCX control is loaded in the CreateChildControls method.

    In the code, the data binding logic is placed in the OnPreRender event to access the custom properties such as AssignedTo and ListName. The values, if specified in the custom properties, are used; otherwise the default values defined in the code are used. Either way, the list items are retrieved by using the SPQuery object in a CAML query.

  3. To deploy the solution, right-click the project name in Solution Explorer and then click Deploy. Visual Studio 2010 builds the solution package and deploys the solution (see Figure 17).

    Figure 17. Deploy the solution

    Deploy the solution

  4. Next, edit the SharePoint page and add the Web Part to the page. Figure 18 shows the output.

    Figure 18. Two Web Parts after being added to the page

    Two Web Parts after being added to the page

    You can also change the custom properties by editing the page and editing the Web Part

Conclusion

The complexity of creating a web part has been greatly reduced through the introduction of the Visual Web Part project template in Visual Studio 2010. In addition to being more intuitive for the developer, the productivity and maintenance gains obtained through designer-based UI development of Web Parts far outweigh the slight performance hit it takes due to loading of the user control and the slight increase in complexity due to addition of user control components to the Web Part and the interaction between them.

Additional Resources

For more information, see the following resources: