12.5. Building a Custom Web Part with AJAX

When adding items to a page that utilizes the Portal Framework, you add the preexisting ASP.NET Web server controls, user controls, or custom controls. In addition to these items, you can also build and incorporate custom Web Parts. Using the WebParts class, you can create your own custom Web Parts. Although similar to ASP.NET custom server control development, the creation of custom Web Parts provides some additional capabilities. Creating a class that inherits from the WebPart class instead of the Control class enables your control to use the new personalization features and to work with the larger Portal Framework, thereby allowing for the control to be closed, maximized, minimized, and more.

To create a custom Web Part control, the first step is to create a project in Visual Studio 2008. From Visual Studio, choose File New Project. This pops open the New Project dialog. In this dialog, select ASP.NET Server Control. Name the project MyStateListBox, and click OK to create the project. You are presented with a class that contains the basic framework for a typical ASP.NET server control. Ignore this framework; you are going to change it so that your class creates a custom Web Parts control instead of an ASP.NET custom server control. Listing 12-4 details the creation of a custom Web Part control that incorporates the use of AJAX.

Example 12-4. Building a Web Part that makes use of AJAX
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

namespace Wrox
{
    public class StateListBox : WebPart
    {
        private String _LabelStartText = " Enter State Name: ";
        readonly TextBox StateInput = new TextBox();
        readonly ListBox StateContents = new ListBox();

        public StateListBox()
        {
            AllowClose = false;
        }

        [Personalizable, WebBrowsable]
        public String LabelStartText
        {
            get { return _LabelStartText; }
            set { _LabelStartText = value; }
        }

        protected override void CreateChildControls()
        {
            Controls.Clear();

            UpdatePanel updatePanel = new UpdatePanel();
            ScriptManager scriptManager = new ScriptManager();

            Label InstructionText = new Label();

InstructionText.BackColor = System.Drawing.Color.LightGray;
            InstructionText.Font.Name = "Verdana";
            InstructionText.Font.Size = 10;
            InstructionText.Font.Bold = true;
            InstructionText.Text = LabelStartText;

            scriptManager.ID = "scriptHandler";
            updatePanel.ID = "refreshName";
            updatePanel.UpdateMode = UpdatePanelUpdateMode.Conditional;
            updatePanel.ChildrenAsTriggers = true;

            Literal LineBreak = new Literal();
            LineBreak.Text = "<br />";

            Button InputButton = new Button();
            InputButton.Text = "Input State";
            InputButton.Click += Button1_Click;

            Literal Spacer = new Literal();
            Spacer.Text = "<p>";

            updatePanel.ContentTemplateContainer.Controls.Add(InstructionText);
            updatePanel.ContentTemplateContainer.Controls.Add(LineBreak);
            updatePanel.ContentTemplateContainer.Controls.Add(StateInput);
            updatePanel.ContentTemplateContainer.Controls.Add(InputButton);
            updatePanel.ContentTemplateContainer.Controls.Add(Spacer);
            updatePanel.ContentTemplateContainer.Controls.Add(StateContents);

            Controls.Add(scriptManager);
            Controls.Add(updatePanel);

            ChildControlsCreated = true;
        }

        private void Button1_Click(object sender, EventArgs e)
        {
            StateContents.Items.Add(StateInput.Text);
            StateInput.Text = String.Empty;
            StateInput.Focus();
        }
    }
}

To review, you first import the System.Web.UI.WebControls.WebParts namespace. The important step in the creation of this custom control is to make sure that it inherits from the WebPart class instead of the customary WebControl class. As stated earlier, this gives the control access to the advanced functionality of the Portal Framework that a typical custom control would not have.

public class StateListBox : WebPart
{

}

You are also going to have to make a reference to the System.Web.Extensions DLL in your project so that you can later instantiate the AJAX pieces that you are going to need for the control.

After the class structure is in place, a few properties are defined, and the constructor is defined as well. The constructor directly uses some of the capabilities that the WebPart class provides. These capabilities will not be available if this custom control has the WebControl class as its base class and is making use of the WebPart.AllowClose property.

public StateListBox()
{
   AllowClose = false;
}

This constructor creates a control that explicitly sets the control's AllowClose property to false — meaning that the Web Part will not have a Close link associated with it when generated in the page. When you use the WebPart class instead of the Control class, in addition to the an AllowClose property, you have access to other WebPart class properties such as AllowEdit, AllowHide, AllowMinimize, AllowZoneChange, and more.

In the example shown in Listing 12-4, you see a custom-defined property: LabelStartText. This property allows you to change the instruction text displayed at the top of the control. The big difference with this custom property is that it is preceded by the Personalizable and the WebBrowsable attributes.

The Personalizable attribute enables the property to be personalized, and the WebBrowsable attribute specifies whether or not the property should be displayed in the Properties window in Visual Studio. The Personalizable attribute can be defined further, using a PersonalizationScope enumeration. The only two possible enumerations — Shared and User — can be defined in the following ways:

[Personalizable(PersonalizationScope.Shared), WebBrowsable]
public String LabelStartText
{
   get { return _LabelStartText; }
   set { _LabelStartText = value; }
}

A PersonalizationScope of User means that any modifications are done on a per user basis. This is the default setting and means that if a user makes modifications to the property, the changes are seen only by that particular user and not by the other users that browse the page. If the PersonalizationScope is set to Shared, changes made by one user will be viewed by others requesting the page.

After you have the properties in place, the next step is to define what is rendered to the page by overriding the CreateChildControls method. In the example in Listing 12-4, the CreateChildControls method renders Label, Literal, TextBox, Button, and ListBox controls.

The CreatChildControls method also includes the AJAX pieces of the control that you must to include to make this work. In the code for this method, you can see that an UpdatePanel and a ScriptManager instance are created. You create the control instances of the Label, Literal, TextBox, Button, and ListBox controls programmatically and then place them inside the UpdatePanel instance through the following code:

updatePanel.ContentTemplateContainer.Controls.Add(InstructionText);
updatePanel.ContentTemplateContainer.Controls.Add(LineBreak);
updatePanel.ContentTemplateContainer.Controls.Add(StateInput);
updatePanel.ContentTemplateContainer.Controls.Add(InputButton);
updatePanel.ContentTemplateContainer.Controls.Add(Spacer);
updatePanel.ContentTemplateContainer.Controls.Add(StateContents);

Once these items are in place within the UpdatePanel instance, the next step is to add everything to the overall control. However, before this occurs, you must add in the ScriptManager control before adding in the controls.

Controls.Add(scriptManager);
Controls.Add(updatePanel);

In addition to defining the properties of some of these controls, a single event is associated with the Button control (Button1_Click) that is also defined in this class.

Now that the custom Web Part control is in place, build the project so that a DLL is created. The next step is to open up the ASP.NET Web project where you want to utilize this new control and, from the Visual Studio Toolbox, add the new control. You can quickly accomplish this task by right-clicking in the Toolbox on the tab where you want the new control to be placed. After right-clicking the appropriate tab, select Choose Items. Click the Browse button and point to the new MyStateListBox.dll that you just created. After this is done, the StateListBox control is highlighted and checked in the Choose Toolbox Items dialog, as illustrated in Figure 12-8.

Figure 12-8. Figure 12-8

Click OK to add the control to your Toolbox. Now you are ready to use this new control as a Web Part control. To do this, simply drag and drop the control into one of your Web Part Zone areas. This does a couple of things. First, it registers the control on the page using the Register directive:

<%@ Register TagPrefix="cc1" Namespace="MyStateListBox.Wrox"
    Assembly="MyStateListBox" %>

Once registered, the control can be used on the page. If you drag it and drop it onto the page's design surface, you get a control in the following construct:

<cc1:StateListBox Runat="server" ID="StateListBox1"
 LabelStartText=" Enter State Name: " AllowClose="False" />

The two important things to notice with this construct are that the custom property, LabelStartText, is present and has the default value in place, and the AllowClose attribute is included. The AllowClose attribute is present only because earlier you made the control's inherited class WebPart and not Control. Because WebPart is set as the inherited class, you have access to these Web Part–specific properties. When you draw the StateListBox control on the page, you can see that, indeed, it is part of the larger Portal Framework and allows for things such as minimization and editing. End users can use this custom Web Part control as if it were any other type of Web Part control. As you can see, you have a lot of power when you create your own Web Part controls.

In addition, because LabelStartText uses the WebBrowsable attribute, you can use the PropertyGridEditorPart control to allow end users to edit this directly in the browser. With this in place, end users will be able to edit the text of the control themselves.

After you run this page and it is generated in the browser, all additions to the ListBox are added using AJAX, as demonstrated with this example request and response:

Request

POST /AspnetAjax/Default1.aspx HTTP/1.1
Accept: */*
Accept-Language: en-us
Referer: http://localhost.:3405/AspnetAjax/Default1.aspx
x-microsoftajax: Delta=true
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Cache-Control: no-cache
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727;
Zune 2.5; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET
CLR 3.5.30729)
Host: localhost.:3405
Content-Length: 454
Connection: Keep-Alive
Pragma: no-cache

WebPartManager1%24StateListBox1%24scriptHandler=WebPartManager1%24StateListBox1%24
refreshName%7CWebPartManager1%24StateListBox1%24ctl04&__WPPS=u&__EVENTTARGET=
&__EVENTARGUMENT=&__VIEWSTATE=%2FwEPDwUKMTk5OTg1OTg1MGRkMlOfVbp1YNYdar89Ds3HJ8m0q
Ds%3D&__EVENTVALIDATION=%2FwEWBAKqu%2FqgBAKRmJmrDAKJlqqyBgLurIydDHmBcWT5yw1PMvS%2
Bp90wfPZzfB2z&WebPartManager1%24StateListBox1%24ctl03=Missouri&__ASYNCPOST=true&
WebPartManager1%24StateListBox1%24ctl04=Input%20State

Response

HTTP/1.1 200 OK
Server: ASP.NET Development Server/9.0.0.0
Date: Mon, 01 Sep 2008 17:13:46 GMT

X-AspNet-Version: 2.0.50727
Cache-Control: private
Content-Type: text/plain; charset=utf-8
Content-Length: 1320
Connection: Close

438|updatePanel|WebPartManager1_StateListBox1_refreshName|<span
style="background-color:LightGrey;font-family:Verdana;font-size:10pt;
font-weight:bold;"> Enter State Name: </span><br />
<input name="WebPartManager1$StateListBox1$ctl03" type="text"
id="WebPartManager1_StateListBox1_ctl03" /><input type="submit"
name="WebPartManager1$StateListBox1$ctl04" value="Input State" /><p>
<select size="4" name="WebPartManager1$StateListBox1$ctl06">
<option value="Missouri">Missouri</option>

</select>|0|hiddenField|__LASTFOCUS||0|hiddenField|__EVENTTARGET||0|hiddenField|
__EVENTARGUMENT||160|hiddenField|__VIEWSTATE|/wEPDwUKMTk5OTg1OTg1MA9kFgICBA9kFgICAQ
9kFgIFDVN0YXRlTGlzdEJveDEPZBYCAgEPZBYCZg9kFgICBQ8QZA8WAWYWARAFCE1pc3NvdXJpBQhNaXNzb
3VyaWdkZGR2AxtIM7SS2C0P9hDKGQH009IShQ==|72|hiddenField|__EVENTVALIDATION|/wEWBQLd7d
asyncPostBackControlIDs|||0|postBackControlIDs|||42|updatePanelIDs||
tWebPartManager1$StateListBox1$refreshName|0|childUpdatePanelIDs|||41|
panelsToRefreshIDs||WebPartManager1$StateListBox1$refreshName|2|
asyncPostBackTimeout||90|13|formAction||Default1.aspx|109|scriptBlock|ScriptPath|
/AspnetAjax/ScriptResource.axd?d=SJ68zay-cFtXy0ZMZpeiURz5pPNxfk17Mof7BD
sGU963y7AcpfHT87QK701rjloY0&t=38f3a940|35|focus||
WebPartManager1_StateListBox1_ctl03|

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset