ptg 474 CHAPTER 10 Using List Controls LISTING 10.16 ShowBulletedListHyperLinks.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.1//EN” “http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd”> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Show BulletedList HyperLinks</title> </head> <body> <form id=”form1” runat=”server”> <asp:BulletedList id=”blWebsites” DisplayMode=”HyperLink” Target=”_blank” Runat=”server”> <asp:ListItem Text=”Yahoo” Value=”http://www.Yahoo.com” /> <asp:ListItem Text=”Google” Value=”http://www.Google.com” /> <asp:ListItem Text=”Deja” Value=”http://www.Deja.com” /> </asp:BulletedList> </form> </body> </html> Each list item has both its Text and Value properties set. The Text property contains the text that displays for the list item, and the Value property contains the URL for the other website. The Target property is set to the value blank. When you click one of the hyperlinks, the page opens in a new window. WARNING The BulletedList control is different from the other List controls because it does not support the SelectedIndex, SelectedItem, and SelectedValue properties. From the Library of Wow! eBook ptg 475 Creating a Custom List Control 10 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, you can build your own. In this section, we create a custom List control named the MultiSelectList control that 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). 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 works with all web browsers, such as Internet Explorer, Firefox, Safari, and Opera. The code for the custom MultiSelectList is contained in Listing 10.17. LISTING 10.17 MultiSelectList.cs using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; FIGURE 10.16 Using the MultiSelectList control. From the Library of Wow! eBook ptg 476 CHAPTER 10 Using List Controls using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; namespace MyControls { /// <summary> /// Enables you to select mulitple list items /// from two list boxes /// </summary> [ValidationProperty(“SelectedItem”)] public class MultiSelectList : ListControl, IPostBackDataHandler { private int _rows = 5; private Unit _UnSelectedWidth = Unit.Parse(“300px”); private Unit _SelectedWidth = Unit.Parse(“300px”); /// <summary> /// This control is contained in a div /// tag /// </summary> protected override HtmlTextWriterTag TagKey { get { return HtmlTextWriterTag.Div; } } protected override void AddAttributesToRender(HtmlTextWriter writer) { writer.AddStyleAttribute(“position”, “relative”); base.AddAttributesToRender(writer); } /// <summary> /// The number of rows of list items to display /// </summary> public int Rows { get { return _rows; } set { _rows = value; } } /// <summary> /// Name passed to client-side script From the Library of Wow! eBook ptg 477 Creating a Custom List Control 10 /// </summary> private string BaseName { get { return ClientID + ClientIDSeparator; } } /// <summary> /// Name of unselected items list box /// </summary> private string UnselectedListName { get { return BaseName + “unselected”; } } /// <summary> /// Name of selected items list box /// </summary> private string SelectedListName { get { return BaseName + “selected”; } } /// <summary> /// Name of hidden input field /// </summary> private string HiddenName { get { return BaseName + “hidden”; } } /// <summary> /// Register client scripts /// </summary> protected override void OnPreRender(EventArgs e) { Page.RegisterRequiresPostBack(this); // Register hidden field Page.ClientScript.RegisterHiddenField ➥ (HiddenName, String.Empty); // Register Include File if (!Page.ClientScript.IsClientScriptIncludeRegistered ➥ (“MultiSelectList”)) Page.ClientScript.RegisterClientScriptInclude(“MultiSelectList”, Page.ResolveUrl(“~/ClientScripts/MultiSelectList.js”)); From the Library of Wow! eBook ptg 478 CHAPTER 10 Using List Controls // Register submit script string submitScript = String.Format(“multiSelectList_submit(‘{0}’)”, BaseName); Page.ClientScript.RegisterOnSubmitStatement(this.GetType(), ➥ this.ClientID, submitScript); base.OnPreRender(e); } /// <summary> /// Render list boxes and buttons /// </summary> protected override void RenderContents(HtmlTextWriter writer) { // 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(); } /// <summary> /// Render the buttons /// </summary> private void RenderButtons(HtmlTextWriter writer) { writer.AddStyleAttribute(“float”, “left”); writer.AddStyleAttribute(HtmlTextWriterStyle.Padding, “10px”); writer.AddStyleAttribute(HtmlTextWriterStyle.TextAlign, “center”); writer.RenderBeginTag(HtmlTextWriterTag.Div); string addScript = String.Format(“return multiSelectList_add(‘{0}’);”, BaseName); writer.AddAttribute(HtmlTextWriterAttribute.Onclick, addScript); writer.AddAttribute(HtmlTextWriterAttribute.Title, “Add Item”); writer.RenderBeginTag(HtmlTextWriterTag.Button); writer.Write(“ >”); From the Library of Wow! eBook ptg 479 Creating a Custom List Control 10 writer.RenderEndTag(); writer.WriteBreak(); string removeScript = String.Format(“return multiSelectList_remove(‘{0}’);”, BaseName); writer.AddAttribute(HtmlTextWriterAttribute.Onclick, removeScript); writer.AddAttribute(HtmlTextWriterAttribute.Title, “Remove Item”); writer.RenderBeginTag(HtmlTextWriterTag.Button); writer.Write(“< ”); writer.RenderEndTag(); writer.RenderEndTag(); } /// <summary> /// Render unselected list box /// </summary> private void RenderUnselected(HtmlTextWriter writer) { writer.AddStyleAttribute(“float”, “left”); writer.AddAttribute(HtmlTextWriterAttribute.Size, _rows.ToString()); writer.AddStyleAttribute(HtmlTextWriterStyle.Width, _UnSelectedWidth.ToString()); writer.AddAttribute(HtmlTextWriterAttribute.Id, UnselectedListName); writer.AddAttribute(HtmlTextWriterAttribute.Name, UnselectedListName); writer.AddAttribute(HtmlTextWriterAttribute.Multiple, “true”); writer.RenderBeginTag(HtmlTextWriterTag.Select); foreach (ListItem item in Items) if (!item.Selected) RenderListItem(writer, item); writer.RenderEndTag(); } /// <summary> /// Render selected list items /// </summary> private void RenderSelected(HtmlTextWriter writer) { writer.AddStyleAttribute(“float”, “left”); writer.AddAttribute(HtmlTextWriterAttribute.Size, _rows.ToString()); writer.AddStyleAttribute(HtmlTextWriterStyle.Width, _SelectedWidth.ToString()); writer.AddAttribute(HtmlTextWriterAttribute.Id, SelectedListName); writer.AddAttribute(HtmlTextWriterAttribute.Name, SelectedListName); writer.AddAttribute(HtmlTextWriterAttribute.Multiple, “true”); writer.RenderBeginTag(HtmlTextWriterTag.Select); foreach (ListItem item in Items) From the Library of Wow! eBook ptg 480 CHAPTER 10 Using List Controls if (item.Selected) RenderListItem(writer, item); writer.RenderEndTag(); } /// <summary> /// Render a list item /// </summary> private void RenderListItem(HtmlTextWriter writer, ListItem item) { writer.AddAttribute(HtmlTextWriterAttribute.Value, item.Value); writer.RenderBeginTag(HtmlTextWriterTag.Option); writer.Write(item.Text); writer.RenderEndTag(); } /// <summary> /// Process postback data /// </summary> public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection) { EnsureDataBound(); ClearSelection(); string values = postCollection[HiddenName]; if (values != String.Empty) { string[] splitValues = values.Split(‘,’); foreach (string value in splitValues) { Items.FindByValue(value).Selected = true; } } return false; } /// <summary> /// Required by the IPostBackDataHandler interface /// </summary> public void RaisePostDataChangedEvent() { } } } From the Library of Wow! eBook ptg 481 Creating a Custom List Control 10 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 renders in the first list box and each selected item renders in the second list box. Furthermore, the MultiSelectList control implements the IPostBackDataHandler inter- face. 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 MultiSelectList.js file. 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 var selectedItems = Array.clone(unselectedList.options); for (var i=0;i < selectedItems.length;i++) { if (selectedItems[i].selected) { var item = unselectedList.removeChild(selectedItems[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 var selectedItems = Array.clone(selectedList.options); for (var i=0;i < selectedItems.length;i++) From the Library of Wow! eBook ptg 482 CHAPTER 10 Using List Controls { if (selectedItems[i].selected) { var item = selectedList.removeChild(selectedItems[i]); unselectedList.appendChild(item); } } // Prevent post return false; } // This function executes when the page // is submitted. It stuffs all of 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(‘,’); } Array.clone = function(arrItems) { var results = []; for (var i=0;i < arrItems.length; i++) results.push(arrItems[i]); return results; }; 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 posts 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=”C#” %> <%@ Register TagPrefix=”custom” Namespace=”MyControls” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.1//EN” From the Library of Wow! eBook ptg 483 Creating a Custom List Control 10 “http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd”> <script runat=”server”> protected void btnSubmit_Click(object sender, EventArgs e) { foreach (ListItem item in MultiSelectList1.Items) if (item.Selected) lblSelected.Text += String.Format(“<li>{0} ➥ ({1})”,item.Text,item.Value); } </script> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Show MultiSelectList</title> </head> <body> <form id=”form1” runat=”server”> <div> <b>Movies:</b> <asp:RequiredFieldValidator id=”val” ControlToValidate=”MultiSelectList1” Text=”Required” Runat=”server” /> <custom:MultiSelectList id=”MultiSelectList1” DataSourceID=”srcMovies” DataTextField=”Title” DataValueField=”Id” Runat=”server” /> <asp:SqlDataSource id=”srcMovies” SelectCommand=”SELECT Id, Title FROM Movies” ConnectionString=”<%$ ConnectionStrings:Movies %>” Runat=”server” /> <p> <asp:Button id=”btnSubmit” Text=”Submit” Runat=”server” OnClick=”btnSubmit_Click” /> </p> From the Library of Wow! eBook . ptg 47 4 CHAPTER 10 Using List Controls LISTING 10.16 ShowBulletedListHyperLinks.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC -/ /W3C//DTD XHTML 1.1//EN” “http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd”>. runat=”server”> < ;asp: BulletedList id=”blWebsites” DisplayMode=”HyperLink” Target=”_blank” Runat=”server”> < ;asp: ListItem Text=”Yahoo” Value=”http://www.Yahoo.com” /> < ;asp: ListItem Text=”Google” Value=”http://www.Google.com”. Text and Value properties set. The Text property contains the text that displays for the list item, and the Value property contains the URL for the other website. The Target property is set to