asp tutorials, asp.net tutorials, sample code, and Microsoft news from 15Seconds
Data Access  |   Troubleshooting  |   Security  |   Performance  |   ADSI  |   Upload  |   Email  |   Control Building  |   Component Building  |   Forms  |   XML  |   Web Services  |   ASP.NET  |   .NET Features  |   .NET 2.0  |   App Development  |   App Architecture  |   IIS  |   Wireless
 
Pioneering Active Server
 Power Search





Active News
15 Seconds Weekly Newsletter
• Complete Coverage
• Site Updates
• Upcoming Features

More Free Newsletters
Reference
News
Articles
Archive
Writers
Code Samples
Components
Tools
FAQ
Feedback
Books
Links
DL Archives
Community
Messageboard
List Servers
Mailing List
WebHosts
Consultants
Tech Jobs
15 Seconds
Home
Site Map
Press
Legal
Privacy Policy
internet.commerce














internet.com
IT
Developer
Internet News
Small Business
Personal Technology
International

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

HardwareCentral
Compare products, prices, and stores at Hardware Central!

Creating a Web Custom Control -- Cont'd
By Conrad Jalali


  • email this article to a colleague
  • suggest an article

    Table of Contents

    • Page 1
      • Prerequisites
      • Introduction
      • Some Background on Controls
      • Planning for Project Reuse
      • Data-Bound Properties
      • CSS and Other Visual Properties

    • Page 2
      • The Render Method
      • The HTML Output by the Control
      • Design-Time Support

    • Page 3
      • Using the Control
      • Conclusion
      • About the Author

    The Render Method

    When you're working on a Web custom control, all of the magic happens in the Render method. In a nutshell, the Render method outputs the HTML to display the control in a Web browser. It's just like using Response.Write in Classic ASP, except that the render method utilizes an HtmlTextWriter object that the host ASPX page passes to it automatically.

    Microsoft took care of all of the plumbing for us, so we don't need to worry about writing any extra code in order to consume the control. You just drop the control on a page, and the page and the control figure out how to talk to each other.

    Let's examine our Render method:

    /// <summary>

    /// Writes out the HTML needed to render this control.

    /// </summary>

    /// <param name="output">The HTML text writer the we will utilize.

    /// This is passed to the control automatically, by the host ASPX page.</param>

    protected override void Render(HtmlTextWriter output)

    {

         try

         {

               // No need for ViewState

               this.EnableViewState = false;

     

               // Make sure that the htmlFieldName is set.

               GetHtmlFieldName();

     

               // Should the control be visible?

               if(this.Visible == true)

               {

                    // Yes. Render the html.

                    BuildCategorizedCheckBoxList(output);

               }

         }

         catch(Exception ex)

         {

               // Something bad happened. Let's tell the user what that was.

               output.Write("Error building CategorizedCheckBoxList:<br>");

               output.Write(ex.Message);

         }

    }

    As you can see, we first disable ViewState support for our control. This will lighten the load of the HTML delivered to the Web browser. Next, we call a method named ReadPostBack, which figures out which checkboxes were checked on the form, if the form was submitted. Finally, if our control is supposed to be visible, we call BuildCategorizedCheckBoxList, which writes the HTML to display the control.

    ReadPostBack determines the name that we're assigning to the checkbox fields, and then looks for this field value in the Request.Form collection. If the Web form containing the control posts back, ASP.NET exposes the Form object as a NameValueCollection that contains all of the fields on the form. If our field is not present, it will equal null, otherwise our code within the "if" statement will run.

    /// <summary>

    /// Retrieves a list of the checkbox values that were selected (checked), if the form was submitted.

    /// This is kind of a poor-man's view state implementation.

    /// But unlike view state, it doesn't add anything to the page weight.

    /// </summary>

    protected void ReadPostBack()

    {

         // See what field name we are assigning to the checkboxes

         GetHtmlFieldName();

     

         // Were any checkboxes checked?

         if(HttpContext.Current.Request.Form[htmlFieldName] != null)

         {

               // Since we assigned the same field name to all of the checkboxes,

               // ASP.NET will give us a comma-delimited list of the selections.

               // First, conver the list to a string array.

               string [] Input = HttpContext.Current.Request.Form[htmlFieldName].Split(',');

     

               // Then, iterate through the array and add each value to our ArrayList.

               for(int i = 0; i < Input.Length; i++)

               {

                    selections.Add(Input[i]);

               }

         }

    }

    When we build the HTML for the checkbox fields (later), you'll see that we're assigning each field the same name. When ASP.NET populates the Request.Form collection, fields with multiple values are neatly packaged as comma-delimited lists. All that we need to do is convert the delimited list into a string array, and then add each value to our selections variable (which is an ArrayList).

    ReadPostBack is also called when the public property, Selections, is accessed. We need to do this because of the sequence of events that fire when a page loads. This permits the hosting page to determine which boxes were checked prior to the control being rendered.

    Here is the GetHtmlFieldName method:

    /// <summary>

    /// Returns the unique field name that we will assogn to the checkboxes, later.

    /// </summary>

    protected void GetHtmlFieldName()

    {

         // Pickup the ID assigned to the control in the consuming ASPX page

         htmlFieldName = this.ID;

    }

    GetHtmlFieldName sets a protected variable called htmlFieldName, using the ID assigned to our control by the consuming ASPX page for its value. You might be wondering why I'm bothering to pickup this ID, but I do this because I don't want to arbitrarily hard-code the name that I'm going to use when we build the checkbox fields.

    If we ensure that the field name is unique, multiple CategorizedCheckBoxList controls can be added to a single web form, and each one will be able to correctly determine which of its checkboxes was checked. Visual Studio.net will ensure (or at least help to ensure) that a programmer doesn't assign the same ID to multiple controls on a page, so the ID property will suit our purpose.

    The method, BuildCategorizedCheckBoxList, is a beast. BuildCategorizedCheckBoxList gets its HtmlTextWriter from our Render method, so that it can write directly to the output stream. It does all of the dirty work necessary to emit the HTML for the control. Let's look at what's going on, section by section.

    We begin by checking to see if there is any data in the DataTable. If not, the keyword, return, will force us to exit from this method.

    /// <summary>

    /// Outputs the HTML for this control.

    /// </summary>

    /// <param name="output"></param>

    protected void BuildCategorizedCheckBoxList(HtmlTextWriter output)

    {

         // Do we have any data?

         if(dataTable == null || dataTable.Rows.Count < 1)

         {

               // There is no data, so there's nothing to render.

               return;

         }

    Next, we look for the columns that were specified for the category, value, and text. If we find these, we assign the indexes to local variables, which we will use later on. Referencing a table column by name is much slower than referencing by index number, which is why we are running this code.

    We deliberately set these column index variables to -1 when they are initialized, because they are all required. If we try to get the value of a column in a DataRow, at the column index -1, the .NET Framework will raise an exception for us.

         // First retrieve the column indexes of the specified columns.

         // Later, we'll get the values that we need using these indexes.

         // This is faster than referencing a column by name.

         int CategoryColumnIndex = -1;

         int TextColumnIndex = -1;

         int ValueColumnIndex = -1;

         for(int i = 0; i < dataTable.Columns.Count; i++)

         {

               if(dataTextColumn == dataTable.Columns[i].ColumnName)

               {

                    TextColumnIndex = i;

               }

              

               if(dataValueColumn == dataTable.Columns[i].ColumnName)

               {

                    ValueColumnIndex = i;

               }

     

               if(dataCategoryColumn == dataTable.Columns[i].ColumnName)

               {

                    CategoryColumnIndex = i;

               }

         }

    Next, we determine whether we're supposed to display all of the categories and their checkboxes in the same table. If so, we write the opening table tag, now:

         /**********************************/

         /* Build the html to display of the items */

         /**********************************/

         // If the consuming page wants one single, shared table, write the opening tag, now.

         if(this.sharedTable == true)

         {

               output.Write(GetTableTag());

         }

    GetTableTag is a helper method that builds the HTML for the opening table tag. More accurately, it returns the value of a private variable called tableTag, whose value, if null, is assigned by this method. For the sake of brevity, I will skip over the details of GetTableTag; however, it's worth noting that since strings are immutable data types, you should always use a StringBuilder object in situations where you would otherwise continually append to a string.

    Moving along, we need to get a distinct list of the categories contained in the DataTable. First, we create a DataView from the DataTable, and sort by the category column. We create a local variable called LastCategory, which we will use to see if we have hit a new category, as we iterate through the rows in the DataView. Whenever we hit a new category, we add it to our Categories ArrayList.

         // Create a string for the "previous" category

         string LastCategory = string.Empty;

     

         // Sort the data by category

         DataView Category = dataTable.DefaultView;

         Category.Sort = this.dataCategoryColumn;

     

         // Assemble a distinct list of the categories found in the data

         ArrayList Categories = new ArrayList();

         for(int i = 0; i < Category.Count; i++)

         {

               if(LastCategory != Category[i][CategoryColumnIndex].ToString())

               {

                    Categories.Add(Category[i][CategoryColumnIndex].ToString());

                    LastCategory = Category[i][CategoryColumnIndex].ToString();

               }

         }

    Now that we have a list of the categories, we'll loop through the list and output the HTML for each category (and its corresponding checkboxes). We do this by creating a DataView, and setting a RowFilter that will limit the rows in the view to those that are in the category that we're working with.

         // Loop through the categories

         for(int i = 0; i < Categories.Count; i++)

         {

               // Get the rows for this category only

               DataView CategoryItems = new DataView(dataTable);

               CategoryItems.RowFilter = String.Format("{0}=\'{1}\'", this.dataCategoryColumn, Categories[i].ToString().Replace("\'","\'\'"));

               CategoryItems.Sort = this.dataTextColumn;

    If we're creating a separate HTML table for each category, we output the opening table tag at this point.

               // If the consuming page wants a separate table for each category,

               // write the opening tabel tag for the current category, now.

               if(this.sharedTable == false)

               {

                    output.Write(GetTableTag());

               }

    Now we need to output the HTML for the current category. The helper method, OutputCategoryRow, renders the HTML needed for this task.

               // Add the category heading to the html

               OutputCategoryRow(output, (string)Categories[i]);

    Things get a little complicated at this point. We know how many items belong to the current category, and we also know how many columns we're supposed to use to display the checkboxes. But we don't know how many rows it will take to display all of the items.

    To determine the number of rows that are needed to display all of the items, we divide the total items in the category by the number of columns that we're going to display. If there was a remainder, we add one to the total rows.

               // Calculate the total number of rows based on the item count and the number of columns

               totalItems = CategoryItems.Count;

               totalRows = totalItems / columns;

     

               // If there was anything left-over as a result of the division, we need to add another row

               if(totalItems % columns > 0)

               {

                    totalRows++;

               }

    Next, we enter a loop for the rows. We create a variable to hold the current index number for the item that we're on. The counter starts at zero. Each time we write the HTML for one of the items, we check to see if it was the last item. (If the CurrentItemIndex equals the total items minus one, we just created the column for the last item.)

    After we have output the HTML for the last item in the current category, we set the CurrentItemIndex to -1. When the CurrentItemIndex is -1 but there are more columns left to display, we output the HTML for an empty table cell for both the checkbox and the text next to the box.

               // Create an integer to hold the index number for the current item

               int CurrentItemIndex = 0;

     

               // Now loop through the rows

               for(int Row = 0; Row < totalRows; Row++)

               {

                    // Determine the starting index for this row.

                    // This is the same calculation that we would perform to handle paging in a grid.

                    int Start = (Row * columns);

     

                    // Create an integer to hold the index number for the current item

                    int CurrentItemIndex = Start;

     

                    // Start the row

                    output.Write("\t");

                    output.Write("<tr class=\"");

                    output.Write(this.rowCssClass);

                    output.Write("\">");

                    output.Write("\n");

     

                    // Column loop

                    for(int Col = 0; Col < columns; Col++)

                    {

                         // Make sure that we haven't hit a blank entry.

                         if(CurrentItemIndex == -1)

                         {

                                 // Add an empty cell (two, actually)

                                 AddEmptyCells(output);

                         }

                         else

                         {

                                 // Now add the checkbox and text

                                 OutputCheckBox(output,

                                       htmlFieldName,

                                       CategoryItems[CurrentItemIndex][TextColumnIndex].ToString(),

                                       CategoryItems[CurrentItemIndex][ValueColumnIndex].ToString(),

                                       IsChecked(CategoryItems[CurrentItemIndex][ValueColumnIndex].ToString())

                                       );

     

                                 // If we have more data left, increment the current index counter.

                                 if(CurrentItemIndex < (totalItems - 1) && CurrentItemIndex != -1)

                                 {

                                       // increment the current index

                                       CurrentItemIndex++;

                                 }

                                 else

                                 {

                                       // We're at the end of the items in the data table.

                                       // Set the value of the current index to -1, which our rendering code

                                       // ignores (creates empty table cells)

                                       CurrentItemIndex = -1;

                                 }

                         }

     

                         // Add a line break

                         output.Write("\n");

                    }

     

    At this point, we've gone through all of the columns in the row, so it's time to end the row.

     

                    // End the row

                    output.Write("\t");

                    output.Write("</tr>\n");

               }

    The loop continues until we've gone through all of the rows. At the end, if we're using a separate table for each category, we end the current category's table, now.

              // Table tag

               if(this.sharedTable == false)

               {

                    output.Write("</table>\n");

               }

         }

    The loop continues until we've finally finished all of the categories. If we are using a shared table, we need to render the closing table tag at the end of this loop.

         // Finish the table

         if(this.sharedTable == true)

         {

               output.Write("</table>\n");

         }

        

         /**********************************/

    }

    Up until this point, I haven't mentioned the helper methods, OutputCheckbox and IsChecked. OutputCheckBox renders the HTML for a table cell containing a checkbox field and another table cell next to it with the corresponding text. I put the checkbox and the text in separate cells just in case the text wraps to a second line. This keeps the alignment of everything nice and neat.

    IsChecked is used to determine whether the checkbox should be displayed with or without a "check". Since our variable, Selections, is an ArrayList, this is very easy:

     

    /// <summary>

    /// Looks for a match between the current value and the list of selected values.

    /// </summary>

    /// <param name="currentValue">The value that we want to look for.</param>

    /// <returns>True if the current value is contained in the selected list. Otherwise, false.</returns>

    protected bool IsChecked(string currentValue)

    {

         // If we have selections, continue

         if(selections != null && selections.Count > 0)

         {

               // Can we find the current value?

               if(selections.IndexOf(currentValue) > -1)

               {

                    // Yes, so this item should be marked as selected (checked)

                    return true;

               }

               else

              {

                    // No, so this item should not be selected

                    return false;

               }

         }

         else

         {

               // Nothing at all was selected, so return false

               return false;

         }

    }

    The HTML Output by the Control

    If you examine the helper methods, GetTableTag, OutputCategoryRow, and OutputCheckBox, you'll probably notice that TABLE tags, TR and TD tags, and the checkbox field tags include the Cascading Style Sheet "class" attribute. We use the CSS classes specified in the control's public properties for these. This allows ASPX pages to control the look and feel of the CategorizedCheckBoxList.

    You may also notice that I add new lines (\n) and tabs (\t) to the HTML for the TABLE, TR, and TD tags. This is not necessary, and it adds to the size of the HTML that the Web browser downloads. But it makes the resultant HTML much easier to read. (View the page source and you'll see.) If you implement this control in a production application, you should probably remove these extra white space characters.

    Design-Time Support

    Ok, so this sounds great so far, but we still have a generic, grey box in the Visual Studio .NET page designer. What's worse, the Properties Window doesn't show any of the properties that our control accepts. To add design-time support to the control, we first need to include code Attributes to the class and property declarations.

    Adding Visual Studio design-time support involves setting code attributes on the public properties:

    [Category("Appearance"),

    DefaultValue(""),

    Description("The CSS Class name for the table row containing each item.")]

    public string RowCssClass

    {

    The bracketed code above the property declaration tells Visual Studio .NET how to display this in the Properties Window:

    Common Attributes

    Category

    Determines the category in which the property appear. Common options are:

    • Appearance
    • Behavior
    • Data

    Description

    The description that will appear at the bottom of the Properties box to help programmers set the property.

    DefaultValue

    Self-explanatory

    Browsable

    Determines whether to show or hide the property in the Properties box. Options are:

    • true
    • false

    As you can see, adding support for the Properties Window is simple.

    Adding design-time support for the control itself to more accurately represent the way the control will be rendered in a browser is a bit more complicated. To do this, we must create a new class that derives from the System.Web.UI.Design.ControlDesigner type, and then add the Designer attribute to our CategorizedCheckBoxList class. The Designer attribute tells Visual Studio that a specific class should be used to render the deign-time HTML for our control.

    The ControlDesigner base class contains a method called, GetDesignTimeHtml. This method builds the HTML used by VS .NET to render the control on pages (in Design view). If we override this method, we can write the HTML ourselves and make the control look however we like.

    We're not striving for absolute fidelity between the look of the CategorizedCheckBoxList in the VS .NET IDE and the live Web application, because of the level of complexity that this would add. But we can still provide support for the basic look and feel of the control, without writing hundreds of lines of code. As Microsoft is fond of saying, "Do more with less."

    Let's take a look at the code for the ControlDesigner:

    /// <summary>

    /// Provides a moderate level of fidelity for the CategorizedCheckBoxList control in the VS.net IDE.

    /// </summary>

    internal class CategorizedCheckBoxListControlDesigner : System.Web.UI.Design.ControlDesigner

    {

         /// <summary>

         /// Provides easy access the properties set in the IDE.

         /// </summary>

         protected CategorizedCheckBoxList ccbl;

     

         /// <summary>

         /// Initializes the designer

         /// </summary>

         /// <param name="component"></param>

         public override void Initialize(IComponent component)

         {

               // Make sure that this designer is attached to a CategorizedCheckBoxList

               if(component is CategorizedCheckBoxList)

               {

                    base.Initialize (component);

                    ccbl = (CategorizedCheckBoxList)component;

               }

         }

    Note that I'm using the "internal" access modifier for this class. The CategorizedCheckBoxLisControlDesigner will be so highly customized that it may only be used for the CategorizedCheckBoxList class. By declaring our ControlDesigner as internal, it may only be used by files within the same .NET Assembly.

    First, we create a CategorizedCheckBoxList variable that we'll use to access the properties that have been set in Visual Studio. Next, we override the Initialize method. If the component using our designer is a CategorizedCheckBoxList, we load the component, and initialize our protected CategorizedCheckBoxList variable.

    When our GetDesignTimeHtml method executes, it generates the HTML necessary to display the CategorizedCheckBoxList with some sample data. Note the code in bold, indicating properties that we retrieve from the CategorizedCheckBoxList:

    /// <summary>

    /// Writes the HTML used be VS.net to display the control at design-time.

    /// </summary>

    /// <returns></returns>

    public override string GetDesignTimeHtml()

    {

         try

         {

               // Start building the HTML

               StringBuilder Sb = new StringBuilder();

        

               // Table

               Sb.Append("<table");

               Sb.Append(" cellspacing=\"");

               Sb.Append(ccbl.CellSpacing.ToString());

               Sb.Append("\"");

               Sb.Append(" cellpadding=\"");

               Sb.Append(ccbl.CellPadding.ToString());

               Sb.Append("\"");

               Sb.Append(" border=\"0\">");

     

               // Category Row

               Sb.Append("<tr><td colspan=\"4\"");

               Sb.Append(" class=\"");

               Sb.Append(ccbl.CategoryCssClass);

               Sb.Append("\"");

               Sb.Append(">Fruit</td></tr>");

     

               // Item Row

               Sb.Append("<tr valign=\"top\">");

               Sb.Append("<td><input type=\"checkbox\" name=\"1\" value=\"1\" class=\"");

               Sb.Append(ccbl.CheckBoxCssClass);

               Sb.Append("\"></td>");

               Sb.Append("<td class=\"");

               Sb.Append(ccbl.TextCssClass);

               Sb.Append("\">Apples</td>");

               Sb.Append("<td><input type=\"checkbox\" name=\"1\" value=\"2\" class=\"");

               Sb.Append(ccbl.CheckBoxCssClass);

               Sb.Append("\"></td>");

               Sb.Append("<td class=\"");

               Sb.Append(ccbl.TextCssClass);

               Sb.Append("\">Oranges</td>");

               Sb.Append("</tr>");

     

               // Item Row

               Sb.Append("<tr valign=\"top\">");

               Sb.Append("<td><input type=\"checkbox\" name=\"1\" value=\"3\" class=\"");

               Sb.Append(ccbl.CheckBoxCssClass);

               Sb.Append("\"></td>");

               Sb.Append("<td class=\"");

               Sb.Append(ccbl.TextCssClass);

               Sb.Append("\">Tangerines</td>");

               Sb.Append("<td></td>");

               Sb.Append("<td class=\"");

               Sb.Append(ccbl.TextCssClass);

               Sb.Append("\"></td>");

               Sb.Append("</tr>");

     

     

               // Category Row

               Sb.Append("<tr><td colspan=\"4\"");

               Sb.Append(" class=\"");

               Sb.Append(ccbl.CategoryCssClass);

               Sb.Append("\"");

               Sb.Append(">Vegetables</td></tr>");

     

               // Item Row

               Sb.Append("<tr valign=\"top\">");

               Sb.Append("<td><input type=\"checkbox\" name=\"2\" value=\"1\" class=\"");

               Sb.Append(ccbl.CheckBoxCssClass);

               Sb.Append("\"></td>");

               Sb.Append("<td class=\"");

               Sb.Append(ccbl.TextCssClass);

               Sb.Append("\">Broccoli</td>");

               Sb.Append("<td><input type=\"checkbox\" name=\"2\" value=\"2\" class=\"");

               Sb.Append(ccbl.CheckBoxCssClass);

               Sb.Append("\"></td>");

               Sb.Append("<td class=\"");

               Sb.Append(ccbl.TextCssClass);

               Sb.Append("\">Green Beans</td>");

               Sb.Append("</tr>");

     

               // Item Row

               Sb.Append("<tr valign=\"top\">");

               Sb.Append("<td><input type=\"checkbox\" name=\"2\" value=\"3\" class=\"");

               Sb.Append(ccbl.CheckBoxCssClass);

               Sb.Append("\"></td>");

               Sb.Append("<td class=\"");

               Sb.Append(ccbl.TextCssClass);

               Sb.Append("\">Potatoes</td>");

               Sb.Append("<td><input type=\"checkbox\" name=\"2\" value=\"4\" class=\"");

               Sb.Append(ccbl.CheckBoxCssClass);

               Sb.Append("\"></td>");

               Sb.Append("<td class=\"");

               Sb.Append(ccbl.TextCssClass);

               Sb.Append("\">Tomatoes</td>");

               Sb.Append("</tr>");

     

               // End the table

               Sb.Append("</table>");

     

               return Sb.ToString();

         }

         catch(Exception ex)

         {

               // Display the error in VS.net, in Design view

               return String.Concat("<h3>Error</h3>Stack Trace:<br>", ex.StackTrace);

         }

    }

    Now all that we have to do is specify that our custom ControlDesigner should be used by the CategorizedCheckBoxList control. Once again, we use a code attribute to accomplish this:

    /// <summary>

    /// The CategorizedCheckBoxList is like a CheckBoxList, but with the ability to categorize the display of items.

    /// </summary>

    [Designer("UsefulControls.CategorizedCheckBoxListControlDesigner"),

    DefaultProperty("DataTable"),

    ToolboxData("<{0}:ccbl runat=server></{0}:ccbl>")]

    public class CategorizedCheckBoxList : System.Web.UI.WebControls.WebControl

    {

         /// <summary>

         /// Initializes a new instance of the CategorizedCheckBoxList class.

         /// </summary>

         public CategorizedCheckBoxList()

         {

               // Init the class

         }

    We're done writing code for our CategorizedCheckBoxList control at this point. Now we can focus our attention on consuming the control.

    << Introduction •       • Using the Control >>

  • Other Articles
    Apr 21, 2004 - Creating a Web Custom Control
    Conrad Jalali shows how to build Web custom controls by creating one that displays checkboxes in a categorized, hierarchical view.
    [Read This Article]  [Top]
    Mar 15, 2004 - Creating a Popup Date Picker
    Conrad Jalali shows how to extend the functionality of the ASP.NET Calendar control to remove some of the annoying postback delays that occur when populating a text box with a date from a popup calendar.
    [Read This Article]  [Top]
    Oct 23, 2003 - Creating a Custom .NET Web Control With Events
    This article covers some of the essentials of building reusable Web controls. Learn how to create a Web control and its custom events and event arguments, as well as how to use the control properly within a page.
    [Read This Article]  [Top]
    Aug 12, 2003 - Creating a Generic Pager Control
    ASP.NET provides only one control that supports paging, the DataGrid. Tomasz Kaszuba shows how to build and implement a custom pager for different controls that change depending on the data source or presentation.
    [Read This Article]  [Top]
    Jun 10, 2003 - Hosting .NET Windows Forms Controls in IE
    Windows Forms within Web pages work in a manner similar to Java applets. Thiru Thangarathinam shows how to host Windows Forms controls in Internet Explorer and how to utilize .NET Code Access Security to configure what the control can do when running within the browser.
    [Read This Article]  [Top]
    May 6, 2003 - Building a Simple Mask Control
    James Culshaw shares his experiences building his first working custom control, a basic mask control that allows input of time values, and offers advice and tips to those just starting out.
    [Read This Article]  [Top]
    Mar 3, 2003 - Creating a Server Control for JavaScript Testing
    Learn how to create an ASP.NET server control that detects if a browser supports JavaScript AND if JavaScript is enabled.
    [Read This Article]  [Top]
    Jan 21, 2003 - Protecting Users from Suspect Textual Data
    Learn the ins and outs of composite controls by creating an application that prevents users from submitting offending text.
    [Read This Article]  [Top]
    Nov 26, 2002 - Introduction to the .NET Speech SDK
    Rob Chartier offers a tour of the .NET Speech SDK Beta 2 and its use of the industry specification SALT. The article shows you how to create a basic speech-enabled Web user control.
    [Read This Article]  [Top]
    Aug 27, 2002 - Creating "Self Populating" Controls
    In this article, Luther Stanton shows how to combine inheritance and server controls to create a self-populating drop-down-list control.
    [Read This Article]  [Top]
    Mailing List
    Want to receive email when the next article is published? Just Click Here to sign up.

    Support the Active Server Industry

    internet.comearthweb.comDevx.commediabistro.comGraphics.com

    Search:

    Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

    Jupitermedia Corporate Info

    Legal Notices, Licensing, Reprints, Permissions, Privacy Policy.
    Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers