Saturday, March 21, 2009

Binding the AJAX FilteredTextboxExtender control to a Textbox control located within a ReorderList control.

I recently ran into a challenge where I had to filter out non-numeric input from a textbox control that was contained in a ReorderList’s ItemTemplate section. We wanted to filter out the keystrokes as the user was typing them instead of waiting for a postback to check the data in the field.

At first I tried dragging the control onto the page and setting the TargetControlID to the ID of the textboxes but when new items were added to the ReorderList, those ID’s would change. Thus my FilteredTextboxExtender could never find the Textbox controls it was supposed to bind to.

To resolve this, I inserted the FilteredTextboxExtenders dynamically so their TargetControlID’s would always match the correct TextBox controls. First, I created an event handler for the ReorderList’s DataBound event, as it was that event that always generated new ID’s for the Textbox controls. Then, in the event handler, I searched the ReorderList’s Items member for the TextBox controls based on the ID’s assigned to them in the markup, using the FindControl() method. Afterwards, I would instantiate the FilteredTextboxExtenders and set their TargetControlID properties to the UniqueID properties of the Textbox controls. The code would look like this:

TextBox multiplier = (TextBox)IngredientDataList.Items[countOfItems - 1].FindControl("New_IngredientMultiplier");
if (null != multiplier)
{
String idToValidate = multiplier.UniqueID;
validateMultiplier = new FilteredTextBoxExtender();
validateMultiplier.TargetControlID = idToValidate;
validateMultiplier.FilterType = FilterTypes.Custom FilterTypes.Numbers;
validateMultiplier.ValidChars = ".";
IngredientDataList.Controls.Add(validateMultiplier);
}

In this example, the bitwise OR operator is used to set the FilterType because the FilterType property is a bit flag, and in this case I had to allow for decimal numbers, so I only let the users enter numbers and a decimal point. As another aside, notice how in my if statement I put the null before the variable I’m checking? This is a defensive programming concept I learnt while at an interview at Microsoft. The purpose for this is if I accidentally forget the exclamation mark, the compilation would fail and I would catch the error immediately. However, if the variable was in front and I forgot the exclamation mark, the line would read:
If (multiplier = null)
Which would always evaluate to true because now it is an assignment as opposed to a condition.

What’s important is that I set the TargetControlID property to the UniqueID property of the Textbox controls, as opposed to just the ID property. It must be UniqueID because this property is assigned by ASP.NET so the FilteredTextBox control will be bound to the proper control after a ReorderList.DataBind() call. The ID property is assigned by the developer and may not actually be the ID of the control if a new item is inserted into the ReorderList.

No comments: