|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionI've always wondered why Microsoft, or any else for that matter, has never provided a native HTML HistoryVersion 1.0 of this web control was based on the element behavior written by Jeremy Bettis at http://www.deadbeef.com/. While Jeremy's behavior worked very well, it didn't include all the features I wanted in a combobox. This update is a total rewrite of that behavior and addresses the following feature requests and bug fixes.
Using the ComboBox ControlNote: This control was developed and tested against IE 6.0. However it is likely IE 5.5 compatible, but will not work with older versions or any non-Microsoft browser. For all the newbie's out there, read and follow the instructions carefully! I will not respond to any inquiries that are answered in this section. First, we have to copy the runtime files, consisting of the combobox.htc and images directory, to their default virtual directory, /$wwwroot/webctrl_client/progstudios/1_1/. You can specify a different location by adding a new element to the <appSettings>
<add key="PROGWEBCONTORLS_COMMONFILEPATH" value="MyVirtualPath" />
</appSettings>
The binary and project files included in the source are based on the .NET Framework 1.1 and Visual Studio 2003. They are not compatible with 1.0 or VS.NET 2002, so you will have to recompile the assembly on your own. To recompile the project in VS.NET 2002, follow the steps outlined below:
To add the assembly to your web project, right click on "References" in the Solution Explorer and locate the DLL by clicking "Browse", or add the project under the "Projects" tab. If you are not using Visual Studio, make sure that you copy the DLL to the bin directory. Once you have the control installed, you can drag and drop the control to the web page in Design mode. The following is the generated HTML code. The first line registers the assembly and associates the " <%@ Register TagPrefix="cc1" Namespace="ProgStudios.WebControls"
Assembly="ProgStudios.WebControls" %>
<html>
<body>
<cc1:combobox id="ComboBox1" runat="server">
<asp:ListItem>ComboBox</asp:ListItem>
</cc1:combobox>
</body>
</html>
You can manually add new items, or like in the demo project, bind it to a <cc1:ComboBox id="ComboBox1" runat="server" DataSource="<%# dataView1 %>"
DataValueField="ProductID" DataTextField="ProductName">
...
protected DataView dataView1;
protected void Page_Load(object sender, System.EventArgs e) {
if (!this.IsPostBack) {
DataSet ds = new DataSet();
FileStream fs = new FileStream(
Server.MapPath("newdataset.xml"),
FileMode.Open,FileAccess.Read);
StreamReader reader = new StreamReader(fs);
ds.ReadXml(reader);
fs.Close();
dataView1 = new DataView(ds.Tables[0]);
ComboBox1.DataBind();
}
}
...
<prog:combobox id="ComboBox1" runat="server"/>
The control also exposes a server side event, <script runat="server" language="c#">
void ComboBox1_OnServerChange(object sender, System.EventArgs e) {
Msg.InnerText = "ServerChange Event Fired: Value=" + ComboBox1.Value;
}
</script>
....
<prog:combobox id="ComboBox1" runat="server"
AutoPostBack="true" OnServerChange="ComboBox1_OnServerChange">
The Inside the C# Web Control CodeIn order to get some free functionality, I decided to inherit from the The rest of the code is pretty straightforward. Besides the exposing of the corresponding server side properties, methods, and events that are available on the web client, I had to implement certain methods to handle all the plumbing. The control must participate in post backs to handle state, therefore, the ...
public virtual void RaisePostDataChangedEvent() {
this.OnServerChange(EventArgs.Empty);
}
public virtual bool LoadPostData(string postDataKey,
NameValueCollection postCollection) {
string sValue = this.Value;
string sPostedValue = postCollection.GetValues(postDataKey)[0];
if (!sValue.Equals(sPostedValue)) {
this.Value = sPostedValue;
return true;
}
return false;
}
...
I also had to override the ...
protected override void LoadViewState(object savedState) {
if (savedState != null) {
object[] State = (object[])savedState;
this.Value = (string) State[0];
ArrayList ItemsList = (ArrayList) State[1];
foreach (object itemText in ItemsList) {
if (this.Items.FindByText((string)itemText)==null) {
ListItem item = new ListItem();
item.Text = (string) itemText;
this.Items.Add(item);
}
}
}
}
protected override object SaveViewState() {
ArrayList ItemsList = new ArrayList();
foreach (ListItem item in this.Items) {
ItemsList.Add(item.Text);
}
object[] savedState = new object[2];
savedState[0] = this.Value;
savedState[1] = ItemsList;
return savedState;
}
...
Writing the control builder class was also a very straightforward task. I inherited from the ...
public override Type GetChildControlType(string tagName,
System.Collections.IDictionary attribs) {
string szTagName = tagName.ToLower();
int colon = szTagName.IndexOf(':');
if ((colon >= 0) && (colon < (szTagName.Length + 1))) {
// Separate the tagname from the namespace
szTagName = szTagName.Substring(colon + 1,
szTagName.Length - colon - 1);
}
if (String.Compare(szTagName, "option", true,
System.Globalization.CultureInfo.InvariantCulture) == 0 ||
String.Compare(szTagName, "listitem", true,
System.Globalization.CultureInfo.InvariantCulture) == 0 ) {
return typeof(System.Web.UI.WebControls.ListItem);
}
// No Type was found, throw an exception
throw new Exception(String.Format(
"Invalid child with tagname \"{0}\"", tagName));
}
The ComboBox Link View BehaviorOK, now we get into the most interesting part of the article. This section will, to some degree, de-mystify what my friend refers as the black art of web development, behavior programming. The current version of the For instance, the <PUBLIC:COMPONENT tagName="COMBOBOX">
...
<STYLE TYPE="text/css">
.clsTextField {border:none;margin-right:1px;margin-left:1px;}
.clsTextFieldCell {background-color:white;border:ridge 1px buttonface;}
.clsTextFieldCell_hover {background-color:white;border:solid 1px navy;}
...
</STYLE>
<body>
<table unselectable="on" ID="tblCombobox"
cellspacing="0" cellpadding="0" border="0">
<tr>
<td unselectable="on" class="clsTextFieldCell"
id="textFieldCell">
<input class="clsTextField" id="textField"
type="text" NAME="textField">
</td>
<td id="dropDownArrowCell" class="clsDropDownCell">
<img width=5 height=3
id="imgArrow" src="images/down_arrow.gif" vspace="2"
hspace="3"/></td>
</tr>
</table>
</body>
</PUBLIC:COMPONENT>
You'll also notice that I define CSS style classes in the HTC file. The
The master element's dimensions are defined by its content fragments. Dynamically created elements, regardless if it's absolutely positioned, affect and are subject to the confines of these dimensions. In the case with the As you can see, this isn't going to work. We need to append in the newly created table the primary document tree instead. Doing so allows us to absolutely position and not alter the master element's dimensions. This also brings up another interesting point, the Finally, I'd like to bring up the Known Issues
| |||||||||||||||||||||||||||||||