Step 1: Identify Server Controls and Extend Common Interface
Identify all the server controls that present data for users to edit, including TextBox, DropDownList, RadioButton, CheckBox, ListBox, RadioButtonList, CheckButtonList, etc. You should also include Literal and Label controls because developers may use them to display immutable fields such as table primary keys. You could expand this list even further. For example, ASP.NET 2.0 comes with a server control called HiddenField that you might include. Developers can also include customized controls in this list by following the changes below. After identifying the server controls, you need to extend them by implementing the following interface:
Public Interface IFormGroup
Property FormGroup() As String
End Interface
IFormGroup supplies the controls with a common interface (other than Control) and serves to single out grouped fields within a container easily. The
FormGroup property could be of type integer, but to make it more generic I made it a string. A
FormGroup typically corresponds to a key column of a table record. The
FormGroup value should be unique for different groups of form data. You implement the
FormGroup property following the same convention as other server control properties.
Public Property FormGroup() As String
Implements IFormGroup.FormGroup
Get
Dim obj As Object
obj = ViewState("FormGroup")
If obj Is Nothing Then
Return Nothing
Else
Return CType(obj, String)
End If
End Get
Set(ByVal Value As String)
ViewState("FormGroup") = Value
End Set
End Property
Step 2: Hook up the Value Change Event Handler
When a form field changes, the postback value change event handler, if any, will be triggered. You should exclude Literal and Label because these two controls present data in read-only fashion. The event name and argument might be different for different controls, but the body of the event handler remains unchanged; it just calls a static function called
AddChangedField.
AddChangedField is a support function responsible for recording the value change information of a control associated with a specific
FormGroup value. I'll provide more detail on the support functions in the next step. For simplicity I'll use a TextBox control as an example.
Private Sub ValueChanged(ByVal sender As Object, _
ByVal args As EventArgs) Handles _
MyBase.TextChanged
xControls.FormGroup.AddChangedField(FormGroup, ID)
End Sub
Step 3: Implement Logic to Store and Query Change Information of Form Data
A number of functions work together to realize this technique, all of which are static, so you can bundle them into a separate FormGroup class, as seen in
Listing 1. The
AddChangedField method records field changes for its associated FormGroup. Note that if the value of FormGroup is missing (e.g.
Nothing in VB.NET), the change information will get lost because each form field must belong to a group. Other similar methods include:
- HasFormGroupChangedChecks whether any control in a form group has changed.
- HasFormGroupFieldChangedChecks if a specific form field in a form group has changed.
- FindFormGroupFieldsAn overloaded function that finds all server controls within a container that belong to the same form group.
- FindChangedFormGroupFieldsSingles out all changed fields in a group of form fields.
So where does the changed information get stored? A NameValueCollection instance records changes of all fields centrally in the global cache
HttpContext.Items.
HttpContext.Items is a page-level cache and accessible to all server controls. The key called
$#!@FormGroup is special and unique and should not be overridden. Each server control has a unique key as well, computed by the
BuildControlKey method based on a control's
FormGroup and the control's
ID.