|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionFor the end user, the Using the ControlThe wwwroot\aspnet_client\UNLV_IAP_WebControls\DropDownCheckList
Several properties are available to customize the display of the control. Use the The rendering of a drop-down image in the display box is dependent on the
The control’s behavior is defined through several additional properties. The The To indicate the text to be displayed when no options are checked, set the
As a subclass of Here is an example of a complete .aspx page which uses the <%@ Page Language="c#" AutoEventWireup="true" %>
<%@ Register TagPrefix="cc1"
Namespace="UNLV.IAP.WebControls"
Assembly="DropDownCheckList" %>
<script runat="server">
void Page_Load(object o, EventArgs e)
{
lblResults.Text = "";
}
void btnSubmit_Click(object o, EventArgs e)
{
string sLabels = dd.SelectedLabelsToString(", ");
string sValues = dd.SelectedValuesToString(", ", "'");
lblResults.Text = "Selected Items: " + sLabels
+ "<br />"
+ "Values: " + sValues;
}
void btnClear_Click(object o, EventArgs e)
{
dd.SelectedValue = null;
}
</script>
<html>
<head>
<title>DropDownCheckList Sample</title>
<style>
.boxStyle
{
border : 2px solid darkBlue;
background-color : lightBlue;
padding : 8px;
}
</style>
</head>
<body>
<form runat="server">
<h3>DropDownCheckList Sample</h3>
<p>Click the drop-down box to select options</p>
<cc1:DropDownCheckList id="dd" runat="server"
RepeatColumns = "2"
DropImageSrc = "dropImage.gif"
DropImagePosition = "Right"
DropDownMode = "OnTopWithShim"
CheckListCssClass = "boxStyle"
CheckListCssStyle = ""
DisplayTextCssStyle = "font-family: Tahoma;"
DisplayTextWidth = "180"
DisplayTextList = "Labels"
Separator = ", "
TruncateString = "..."
TextWhenNoneChecked = "--select--"
>
<asp:ListItem text="North" value="N" />
<asp:ListItem text="South" value="S" />
<asp:ListItem text="East" value="E" />
<asp:ListItem text="West" value="W" />
<asp:ListItem text="Northeast" value="NE" />
<asp:ListItem text="Southeast" value="SE" />
<asp:ListItem text="Northwest" value="NW" />
<asp:ListItem text="Southwest" value="SW" />
</cc1:DropDownCheckList>
<p>
<asp:Button id="btnSubmit" runat="server" text="Submit Choices"
onClick="btnSubmit_Click" />
<asp:Button id="btnClear" runat="server" text="Clear Choices"
onClick="btnClear_Click" />
</p>
<p><asp:Label id="lblResults" runat="server" /></p>
</form>
</body>
</html>
Inheriting from CheckBoxListThere are positive and negative ramifications to subclassing On the minus side, we do not have access to individual To work within this constraint, yet still take advantage of the protected override void Render(HtmlTextWriter output)
{
. . .
// next, render the contents of the checkboxlist;
// do we need to render values?
if (_displayTextList == DisplayTextListEnum.Values)
{
// if so, we need to render to a string first
// so we can include our own values attribute
StringWriter sw = new StringWriter();
HtmlTextWriter wr = new HtmlTextWriter(sw);
base.Render(wr);
string sHtml = sw.ToString();
wr.Close();
sw.Close();
// now modify the code to include custom attributes
sHtml = ModifyRenderedCheckboxes(sHtml);
// and write to the output stream
output.Write(sHtml);
}
else
{
// if we're not rendering custom value attributes,
// just output the checkboxes to the output stream
base.Render(output);
}
. . .
}
The method protected string ModifyRenderedCheckboxes(string sHtml)
{
// use a regular expression to identify in the form:
//<input id="DropDownCheckList1_0" type="checkbox"
string s = string.Format("input id=\"{0}_(?<" +
"index>\\d+)\"\\s+type=\"checkbox\"\\s+",
this.ClientID);
Regex r = new Regex(s, RegexOptions.IgnoreCase);
MatchCollection matches = r.Matches(sHtml);
foreach (Match m in matches)
{
int index = Convert.ToInt32(m.Groups["index"].Value);
sHtml = Regex.Replace(sHtml, m.Value, m.Value + " value=\""
+ this.Items[index].Value + "\" ");
}
return sHtml;
}
Challenges Resolved in the Client-Side JavaScriptOne of the driving goals of this control was to maintain cross-platform compatibility, at least with the recent versions of Internet Explorer (6.x), Netscape (7.x and 8.x), and Firefox (1.x). This goal impacted several aspects of the client-side script. (A note about Netscape 6.x: The control as presented does not work with Netscape 6 for one important reason. Netscape 6 does not submit form inputs in a Appending an ellipsis when the display text is too wideAs there may be more checked options to list than width to display them, it is useful to append an indicator to the truncated text. Typically, an ellipsis (…) is used under such conditions. Internet Explorer supports a To ensure support for Firefox and Netscape, and to allow for the customizable function DDCL_DropDownCheckList_DisplayCheckedItems()
{
var sLabel = "";
var sCurrent = "";
var sFull = "";
var sBefore = "";
var sCompText = "";
var bEllipsisAdded = false;
// get all checkboxes in the checklist
var e = this.divCheckboxes.getElementsByTagName("input");
// clear the display text
this.divText.innerHTML = "";
// clear the title (tooltip) attribute
this.divDisplayBox.title = "";
// loop through all checkboxes in the checklist to see
// which ones are checked;
for (var i=0; i<e.length; i++)
{
if (e[i].type == "checkbox" && e[i].checked)
{
// if the checkbox is checked, get its associated label text
if (this.displayList == DDCL_DISPLAYTEXTLIST_LABELS)
// get the label for the checkbox
sLabel = this.GetLabelForCheckbox(e[i]);
else
// get the value for the checkbox
sLabel = e[i].value;
// add the list separator if necessary
if (sCurrent != "")
{
sCurrent += this.separator;
sFull += this.separator;
}
sFull += sLabel;
sCurrent += sLabel;
if (bEllipsisAdded == false)
{
// add this one to the text box, then test for the
// width against the display box
this.divText.innerHTML = "<nobr>" + sCurrent + "</nobr>";
if (this.divText.offsetWidth > this.boundingBoxWidth
&& this.allowExpand == false)
{
// too big; shrink by what we can and add the ellipsis
// (or other trunacte string)
while (this.divText.offsetWidth > this.boundingBoxWidth
&& sCurrent.length > 0)
{
sCurrent = sCurrent.substr(0, sCurrent.length - 1);
this.divText.innerHTML = "<nobr>" + sCurrent
+ this.truncateString + "</nobr>";
}
// and indicate the ellipsis (or other truncate text)
// has been added
bEllipsisAdded = true;
}
}
}
}
// finally, if there are no contents, display the textWhenNone message
if (this.divText.innerHTML == "")
{
if(this.textWhenNone == "")
this.divText.innerHTML = " ";
else
this.divText.innerHTML = this.textWhenNone;
}
// if we added the ellipsis, set the title attribute to the full string
// (which will display as a tooltip in most browsers)
if (bEllipsisAdded)
this.divDisplayBox.title = sFull;
else
this.divDisplayBox.title = "";
}
For each checked box, its label or value (depending on the server-side property This script also references the function function DDCL_DropDownCheckList_GetLabelForCheckbox(elem)
{
var e = this.divCheckboxes.getElementsByTagName("label");
for (var i=0; i<e.length; i++)
{
if (e[i].htmlFor == elem.id)
{
for (var j=0; j<e[i].childNodes.length; j++)
{
if (e[i].childNodes[j].nodeType == 3) //text type
{
return e[i].childNodes[j].nodeValue;
}
}
}
}
// still here? no <label> for this checkbox then
return null;
}
Allowing a click outside the checklist to collapse the listA click in the display box will expand the checklist. In my first incarnation of this control, a second click in the display box was required to collapse it again. This quickly became an annoyance upon initial testing, as I found myself in the habit of clicking in the white space next to the checklist expecting (subconsciously?) the list to collapse on its own. Perhaps this is just my fixation, but it seemed appropriate with this control to add the functionality of automatically collapsing the list upon a click outside the list. To accomplish this, the client-side constructor adds a function DDCL_DropDownCheckList(...)
{
. . .
// if the browser supports bubbling events, install a default click
// handler for the document too, that will close the checkboxes div
// if there is a click outside it
if (document.attachEvent)
{
document.attachEvent('onclick'
, function() { eval("DDCL_HandleDocumentClick('" + id + "');") }
);
}
else if (document.addEventListener)
{
document.addEventListener('click'
, function() { eval("DDCL_HandleDocumentClick('" + id + "');") }
, false);
}
. . .
}
An event added to the The function DDCL_HandleDocumentClick(id)
{
var obj = DDCL_GetObject(id);
if (obj)
{
if (obj.inCheckboxDiv == true)
obj.inCheckboxDiv = false;
else
obj.CloseCheckList();
}
}
Using a shim for Internet ExplorerCustom
The One common workaround to this is to use JavaScript to loop through all Fortunately, Joe King, working for Coalesys, Inc., developed and published a different solution to this problem which works for Internet Explorer versions 5.5 and higher [1]. The technique employs a “shim” in the form of an The function DDCL_DropDownCheckList_OpenCheckList()
{
// open the checkboxlist; first, position it below the displaybox
// determine the position based on the dropDownMode
if (this.dropDownMode == DDCL_DROPDOWNMODE_INLINE)
{
// inline mode; we're already setup as we need to be
this.divCheckboxes.style.display = "block";
}
else
{
// on top modes; position the box
this.divCheckboxes.style.left = DDCL_findPosX(this.divDisplayBox);
this.divCheckboxes.style.top = DDCL_findPosY(this.divDisplayBox)
+ this.divDisplayBox.offsetHeight;
this.divCheckboxes.style.display = "block";
// if we want the shim, apply that now
if (this.dropDownMode == DDCL_DROPDOWNMODE_ONTOPWITHSHIM)
{
this.shim.style.width = this.divCheckboxes.offsetWidth;
this.shim.style.height = this.divCheckboxes.offsetHeight;
this.shim.style.top = this.divCheckboxes.style.top;
this.shim.style.left = this.divCheckboxes.style.left;
this.shim.style.zIndex = this.divCheckboxes.style.zIndex - 1;
this.shim.style.display = "block";
}
}
}
I would also like to acknowledge and thank Peter-Paul Koch [2] for his very useful SummaryThe Acknowledgements
| ||||||||||||||||||||||