Leon's Weblog

April 13, 2013

Template Design of an ASP.NET Search/Edit page

Filed under: Software Dev — Leon @ 2:41 pm

Forms Whenever I am working on a simple ASP.NET web-page to allow a user to search and edit a specific database table I use the following design template to facilitate implementation. I find that it works for most simple web apps that I need. The sample code files are available for download at the end of the article.

Goals
• ASP.NET page that allows users to search data from a single table and edit the results (insert is not covered for simplicity but can be easily adapted to the design)
• Client and server side data validation

Prerequisites
• .NET Framework 4.0
• Ajax Control Toolkit

Design
The page is divided into several Update Panels so that partial page rendering can be enabled to dynamically load sections of the page at a time. The main sections are the search parameters section, search results section and record details section. The search results are displayed in a GridView control which allows the user to drill down on any record to view or edit the details. The details are displayed in a FormView control that is popped up in a modal window. Most of the implementation details are self explanatory so I will only review the tricky parts.

Data Binding
Data binding controls in ASP.NET is not necessarily complicated but it often helps to have more control of the process instead of relying on the default way the controls get rendered. For example, we can tie into the RowDataBind event and highlight data in the grid or hide certain columns depending on the user’s application permissions. Another nice trick is to highlight or blink the row of the search results that was recently edited. To implement this we have to store the ID of the record which was last edited and then, as each row in the grid is bound to the data, check if the current row’s record ID matches the stored ID. If there is a match, a JavaScript function call is triggered on the client at that position when the page completes the postback. Finally, on the client side, the JavaScript function will change the color of the specified row and then change it back after a short period of time. The logic for this is bellow:

Server Side (ASP.NET)

Protected Sub gridSearchResults_RowDataBound(ByVal sender As Object, _
                  ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gridSearchResults.RowDataBound
    'stop if not a data row or footer
    If e.Row.RowType <> DataControlRowType.DataRow And e.Row.RowType <> DataControlRowType.Footer Then
        Return
    End If

    'for regular rows
    If e.Row.FindControl("cmdEdit") IsNot Nothing Then
        'highlight and fade last edited row
        Dim drv As DataRowView = DirectCast(e.Row.DataItem, DataRowView)
        Dim ID As Integer = drv("ID")
        If CurrentRecordId = ID Then
            Dim script As String = "hightlightRow('" & sender.ClientID & "'," & e.Row.RowIndex & ");"
            ScriptManager.RegisterStartupScript(UpdatePanelDetails, _
                          UpdatePanelDetails.GetType(), "hightlightRow", script, True)
        End If
    End If
End Sub

Client Side (JavaScript)

function hightlightRow(tableName, rowIndex) {
    var table = document.getElementById(tableName);
    var row = table.rows[rowIndex+1];
    var currentColor = row.style.backgroundColor;

    //set highlight color and fade back after 1.5 seconds
    row.style.backgroundColor = '#A1D4FF';
    window.setTimeout(function () { row.style.backgroundColor = currentColor; }, 1500);
}

Handling the data binding event for a FormView control is also useful because this gives you greater control over the nested objects. For example, to dynamically load a dropdown list’s items when editing a selected record we can do the following:

Protected Sub viewDetails_DataBound(sender As Object, e As System.EventArgs) Handles viewDetails.DataBound
    If viewDetails.CurrentMode = FormViewMode.Edit Then
        'fill edit parameters and load saved values
        Dim cmbEditField2 As DropDownList = CType(viewDetails.FindControl("cmbEditField2"), DropDownList)
        Dim Field2 As String = CType(DataBinder.Eval(viewDetails.DataItem, "Field2"), String)

        'bind drop down and set value
        cmbEditField2.DataSource = GetData()
        cmbEditField2.DataTextField = "Description"
        cmbEditField2.DataValueField = "Code"
        cmbEditField2.DataBind()
        cmbEditField2.SelectedValue = Field2
    End If
End Sub

Modal Popup Window
We could just leave the details form positioned directly below the search results table but making it a modal popup greatly improves the user experience. With the AJAX Control Toolkit, implementing this functionality is trivial using the ModalPopupExtender. This article provides a nice rundown of how this works.

Data Validation
Setting the Page property EnableEventValidation to false will make the page load faster (and resolves some problems with the AJAX Control Toolkit controls) but it forces us to implement our own business logic for validation of user input. I prefer to implement validation at several places on both the server and client sides to improve the data quality, system security, as well as the user experience. On the client side, validation controls are used to ensure that user input (search parameters as well as edits to the table) match basic requirements (e.g. required fields, data type, length of string etc…). More complicated validation rules are implemented using the CustomValidator control which calls a server side validation function. One caveat when using this control inside a modal popup window is that the validation function has to explicitly keep the modal window open if validation fails (otherwise the window closes but the user data is lost). Finally, before any user data is sent to the SQL server, the values are validated one last time on the server side to check for SQL Injection attempts and other business logic.

Exporting Data to Excel
A convenient method for allowing the user to download data from the table (i.e. the search results) to a spreadsheet is to write the data back directly to the Response object as part of the postback as follows.

Response.Clear()
Response.ContentType = "application/xls"
Response.AddHeader("content-disposition", "attachment; filename=""Extract.xls""")
Response.Write("data") 'loop though all the data here
Response.End()

To generate the output, a simple comma separated values list is the easiest solution. For a little more flair; however, we can generate a HTML table and trick Microsoft Excel to open the file as a formatted document (that’s why the content type as well as the file extension above are set to “xls” instead of “txt”). Since we are using partial page rendering, another important step is to force the control that will be executing this code when clicked to perform a full page postback (instead of an asynchronous postback) using the following command in the page_load event.

scriptmanager1.RegisterPostBackControl(cmdExport)

Code
The sample code files are provided below:
SearchEditTemplate.aspx
SearchEditTemplate.aspx.vb
SearchEditTemplate.js

No Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a comment