Creating a Custom List Control


All the List controls inherit from the base ListControl class. If you are not happy with the existing List controls, there is nothing to prevent you from building your own.

In this section, we create a custom List control named the MultiSelectList control. This control renders two list boxes and an Add and Remove button. You can click the buttons to move items between the two list boxes (see Figure 10.16).

Figure 10.16. Using the MultiSelectList control.


The custom control uses client-side JavaScript to move the items between the two list boxes. Using JavaScript enables you to avoid posting the page back to the server each time a list item is moved. The client-side JavaScript is standards compliant so it will work with Internet Explorer 6.0, FireFox 1.0, and Opera 8.0.

The code for the custom MultiSelectList is contained in Listing 10.17.

Listing 10.17. MultiSelectList.vb

[View full width]

Imports System Imports System.Web Imports System.Web.UI Imports System.Web.UI.WebControls Imports System.Collections.Specialized Namespace myControls     ''' <summary>     ''' Enables you to select mulitple list items     ''' from two list boxes     ''' </summary>     <ValidationProperty("SelectedItem")> _     Public Class MultiSelectList         Inherits ListControl         Implements IPostBackDataHandler         Private _rows As Integer = 5         ''' <summary>         ''' This control is contained in a div         ''' tag         ''' </summary>         Protected Overrides ReadOnly Property TagKey() As HtmlTextWriterTag             Get                 Return HtmlTextWriterTag.Div             End Get         End Property         ''' <summary>         ''' The number of rows of list items to display         ''' </summary>         Public Property Rows() As Integer             Get                 Return _rows             End Get             Set(ByVal Value As Integer)                 _rows = Value             End Set         End Property         ''' <summary>         ''' Name passed to client-side script         ''' </summary>         Private ReadOnly Property BaseName() As String             Get                 Return ClientID & ClientIDSeparator             End Get         End Property         ''' <summary>         ''' Name of unselected items list box         ''' </summary>         Private ReadOnly Property UnselectedListName() As String             Get                 Return BaseName & "unselected"             End Get         End Property         ''' <summary>         ''' Name of selected items list box         ''' </summary>         Private ReadOnly Property SelectedListName() As String             Get                 Return BaseName & "selected"             End Get         End Property         ''' <summary>         ''' Name of hidden input field         ''' </summary>         Private ReadOnly Property HiddenName() As String             Get                 Return BaseName & "hidden"             End Get         End Property         ''' <summary>         ''' Register client scripts         ''' </summary>         Protected Overrides Sub OnPreRender(ByVal e As EventArgs)             Page.RegisterRequiresPostBack(Me)             ' Register hidden field             Page.ClientScript.RegisterHiddenField(HiddenName, String.Empty)             ' Register Include File             If Not Page.ClientScript.IsClientScriptIncludeRegistered("MultiSe- lectList") Then                 Page.ClientScript.RegisterClientScriptInclude("MultiSelectList", Page .ResolveUrl("~/ClientScripts/MultiSelectList.js"))             End If             ' Register submit script             Dim submitScript As String = String.Format("multiSelectList_submit('{0}')",  BaseName)             Page.ClientScript.RegisterOnSubmitStatement(Me.GetType(), Me.ClientID, submitScript)             MyBase.OnPreRender(e)         End Sub         ''' <summary>         ''' Render list boxes and buttons         ''' </summary>         Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)             ' Render Unselected             RenderUnselected(writer)             ' Render Buttons             RenderButtons(writer)             ' Render Selected             RenderSelected(writer)             ' Render clear break             writer.AddStyleAttribute("clear", "both")             writer.RenderBeginTag(HtmlTextWriterTag.Br)             writer.RenderEndTag()         End Sub         ''' <summary>         ''' Render the buttons         ''' </summary>         Private Sub RenderButtons(ByVal writer As HtmlTextWriter)             writer.AddStyleAttribute("float", "left")             writer.AddStyleAttribute(HtmlTextWriterStyle.Width, "20%")             writer.AddStyleAttribute(HtmlTextWriterStyle.TextAlign, "center")             writer.RenderBeginTag(HtmlTextWriterTag.Div)             Dim addScript As String = String.Format("return multiSelectList_add('{0}');",  BaseName)             writer.AddAttribute(HtmlTextWriterAttribute.Onclick, addScript)             writer.AddAttribute(HtmlTextWriterAttribute.Title, "Add Item")             writer.RenderBeginTag(HtmlTextWriterTag.Button)             writer.Write("--&gt;")             writer.RenderEndTag()             writer.WriteBreak()             Dim removeScript As String = String.Format("return multiSelectList_remove('{0 }');", BaseName)             writer.AddAttribute(HtmlTextWriterAttribute.Onclick, removeScript)             writer.AddAttribute(HtmlTextWriterAttribute.Title, "Remove Item")             writer.RenderBeginTag(HtmlTextWriterTag.Button)             writer.Write("&lt;--")             writer.RenderEndTag()             writer.RenderEndTag()         End Sub         ''' <summary>         ''' Render unselected list box         ''' </summary>         Private Sub RenderUnselected(ByVal writer As HtmlTextWriter)             writer.AddStyleAttribute("float", "left")             writer.AddStyleAttribute(HtmlTextWriterStyle.Width, "40%")             writer.RenderBeginTag(HtmlTextWriterTag.Div)             writer.AddAttribute(HtmlTextWriterAttribute.Size, _rows.ToString())             writer.AddStyleAttribute(HtmlTextWriterStyle.Width, "100%")             writer.AddAttribute(HtmlTextWriterAttribute.Id, UnselectedListName)             writer.AddAttribute(HtmlTextWriterAttribute.Name, UnselectedListName)             writer.RenderBeginTag(HtmlTextWriterTag.Select)             For Each item As ListItem In Items                 If Not item.Selected Then                     RenderListItem(writer, item)                 End If             Next             writer.RenderEndTag()             writer.RenderEndTag()         End Sub         ''' <summary>         ''' Render selected list items         ''' </summary>         Private Sub RenderSelected(ByVal writer As HtmlTextWriter)             writer.AddStyleAttribute("float", "left")             writer.AddStyleAttribute(HtmlTextWriterStyle.Width, "40%")             writer.RenderBeginTag(HtmlTextWriterTag.Div)             writer.AddAttribute(HtmlTextWriterAttribute.Size, _rows.ToString())             writer.AddStyleAttribute(HtmlTextWriterStyle.Width, "100%")             writer.AddAttribute(HtmlTextWriterAttribute.Id, SelectedListName)             writer.AddAttribute(HtmlTextWriterAttribute.Name, SelectedListName)             writer.RenderBeginTag(HtmlTextWriterTag.Select)             For Each item As ListItem In Items                 If item.Selected Then                     RenderListItem(writer, item)                 End If             Next             writer.RenderEndTag()             writer.RenderEndTag()         End Sub         ''' <summary>         ''' Render a list item         ''' </summary>         Private Sub RenderListItem(ByVal writer As HtmlTextWriter, ByVal item As ListItem)             writer.AddAttribute(HtmlTextWriterAttribute.Value, item.Value)             writer.RenderBeginTag(HtmlTextWriterTag.Option)             writer.Write(item.Text)             writer.RenderEndTag()         End Sub         ''' <summary>         ''' Process postback data         ''' </summary>         Public Function LoadPostData(ByVal postDataKey As String, ByVal postCollection As  NameValueCollection) As Boolean Implements IPostBackDataHandler.LoadPostData             EnsureDataBound()             ClearSelection()             Dim values As String = postCollection(HiddenName)             If values <> String.Empty Then                 Dim splitValues() As String = values.Split(","c)                 For Each value As String In splitValues                     Items.FindByValue(value).Selected = True                 Next             End If             Return False         End Function         ''' <summary>         ''' Required by the IPostBackDataHandler interface         ''' </summary>         Public Sub RaisePostDataChangedEvent() Implements IPostBackDataHandler.RaisePostDataChangedEvent         End Sub     End Class  End Namespace

Notice that the TagKey property of the base ListControl class is overridden. The elements of the control are contained in an HTML <div> tag.

The MultiSelectList renders its user interface in the RenderContents() method. This method renders the two list boxes and button controls. Each unselected list item is rendered in the first list box and each selected item is rendered in the second list box.

Furthermore, the MultiSelectList control implements the IPostBackDataHandler interface. When a user posts a page that contains the MultiSelectList control to the server, each item that the user selected is retrieved and the Items collection of the List control is updated.

The control takes advantage of a client-side JavaScript library contained in a file named MultiSelectList.js. This JavaScript library is registered in the control's OnPreRender() method. The MultiSelectList.js library is contained in Listing 10.18.

Listing 10.18. MultiSelectList.js

function multiSelectList_add(baseName) {     var unselectedList = document.getElementById(baseName + 'unselected');     var selectedList = document.getElementById(baseName + 'selected');     // Copy selected items     for (var i=0;i < unselectedList.options.length;i++)     {         if (unselectedList.options[i].selected)         {            var item = unselectedList.removeChild(unselectedList.options[i]);            selectedList.appendChild(item);         }     }     // Prevent post     return false; } function multiSelectList_remove(baseName) {     var unselectedList = document.getElementById(baseName + 'unselected');     var selectedList = document.getElementById(baseName + 'selected');     // Copy unselected items     for (var i=0;i < selectedList.options.length;i++)     {         if (selectedList.options[i].selected)         {             var item = selectedList.removeChild(selectedList.options[i]);             unselectedList.appendChild(item);         }     }     // Prevent post     return false; } // This function executes when the page // is submitted. It stuffs all the // selected items into a hidden field function multiSelectList_submit(baseName) {     var hidden = document.getElementById(baseName + 'hidden');     var selectedList = document.getElementById(baseName + 'selected');     var values = new Array();     for (var i=0;i<selectedList.options.length;i++)         values.push(selectedList.options[i].value);     hidden.value = values.join(',');  }

Listing 10.18 contains three JavaScript functions. The first two functions simply move list items from one list box to the other list box. The multiSelectList_submit() function is called immediately before a page containing the MultiSelectList control is posted to the server. This control records each of the selected list items (the items in the second list box) to a hidden form field.

The page in Listing 10.19 illustrates how you can use the MultiSelectList control.

Listing 10.19. ShowMultiSelectList.aspx

<%@ Page Language="VB" %> <%@ Register TagPrefix="custom" Namespace="myControls" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server">     Protected  Sub btnSubmit_Click(ByVal sender As Object, ByVal e As EventArgs)         For Each item As ListItem In MultiSelectList1.Items             If item.Selected Then                 lblSelected.Text &= String.Format("<li>{0} ({1})", item.Text, item.Value)             End If         Next     End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head  runat="server">     <title>Show MultiSelectList</title> </head> <body>     <form  runat="server">     <div>     <b>Movies:</b>     <custom:MultiSelectList                  DataSource         DataTextField="Title"         DataValueField="Id"         Style="width:400px"         Runat="server" />     <asp:RequiredFieldValidator                  ControlToValidate="MultiSelectList1"         Text="Required"         Runat="server" />     <asp:SqlDataSource                  SelectCommand="SELECT Id, Title FROM Movies"         ConnectionString="<%$ ConnectionStrings:Movies %>"         Runat="server" />     <p>     <asp:Button                  Text="Submit"         Runat="server" OnClick="btnSubmit_Click" />     </p>     <hr />     <asp:Label                  EnableViewState="false"         Runat="server" />     </div>     </form> </body> </html>

In the page in Listing 10.19, the MultiSelectList control is bound to a SqlDataSource control, which represents the contents of the Movies database table. You can select movie titles in the MultiSelectList control by moving movie titles from one list box to the second list box. When you click the Submit button, the selected movies are displayed in a Label control.




ASP. NET 2.0 Unleashed
ASP.NET 2.0 Unleashed
ISBN: 0672328232
EAN: 2147483647
Year: 2006
Pages: 276

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net