Asp.NET Tutorials
Home > Asp.Net开发 > Ajax.Net Auto-fill User Control

Hot archives

Ajax.Net Auto-fill User Control

Dropdown boxes solve a lot of data entry problems.  They ensure that the data that is being entered on a form come from a controlled source.  From a UI developer’s perspective, its input that you don’t have to validate.  But what happens if you need to fill the dropdown box with hundreds (if not thousands) of selections.  If you’ve ever tried to do this, you will know that this will slow down your page tremendously, and if your users are on a slow connection – then forget it.  You will be hunted down, chopped up, and burned on a stick (if they had their way)

 

An elegant solution to this dilemma is to force the user to start typing the first few letters of the item that they are selecting.  Your application should then be smart enough to take those initial letters, filter the selection, and then return the matching records as a list that the user can choose from.   This can be achieved with AJAX (Asynchronous Javascript and XML)  AJAX is not a new technology.  It’s a compilation of old technologies packaged up into a new coding technique.  You can read up more about it from this other article .  My article will show you how to use AJAX to create a control that you can use to solve the dilemma we explained above.

 

To start, you will need to download the AJAX.Net Library.  If you want to just start using the control, then you can download the user control here: http://www2.mybridgepoint.com/jgavilan/attachments/AutoFillDropDownAjax.zip  Below, I will explain how the control is built.

 

 

Web.config:

 

Ajax.net HTTPHandler

The Ajax.net library is a custom http handler.  In order for your application to recognize the calls made by the Javascript that the library auto-generates, you need to tell your application to use the AJAX.dll file to handle those specific XMLHttp Calls.  Put the following HTTPHandler in your web.config file, like this:

 

       <system.web>

              <httpHandlers>

                     <add verb="POST,GET" path="ajax/*.ashx" type="Ajax.PageHandlerFactory, Ajax"/>

              </httpHandlers>

       </system.web>

 

User Control (Code-Behind File):

 

Register The Control for the Ajax.net Library:

Controls that are to be called by the ajax javascript methods need to be registered, so that the library can dynamically generate the necessary javascript classes on the fly.  These classes are what the browser will be interacting with, and they will handle the Asynchronous XMLHTTP calls back to the web server.

 

    Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Ajax.Utility.RegisterTypeForAjax(GetType(Autofill))

    End Sub

 

 

Ajax Methods:

 

#Region "Ajax Methods"

    'The object below will be returned by the ajax vb.net class to the

    'calling javascript function

    <Serializable()> _

    Public Class clsPOS

        Public DropDownHTML As String = ""

        Public TextboxValue As String = ""

        Public Matches As Integer = 0

        Public TextBoxID As String = ""

        Public Value1 As String = ""

        Public Value2 As String = ""

    End Class

 

    'This method will be asynchronously, and indirectly called by the javascript 

    'function, and will ultimately return a javascript object of type clsPOS to the

    'javascript caller

    <Ajax.AjaxMethod(Ajax.HttpSessionStateRequirement.ReadWrite)> _

    Public Function UpdateDropdownList(ByVal Filter As String) As clsPOS

        Dim ret As clsPOS = New clsPOS()

        Dim sb As StringBuilder = New StringBuilder()

 

        If Filter <> "" Then

            Dim dt As DataTable = GetFilteredData("UserName like '" & Filter & "%'")

            ret.Matches = dt.Rows.Count

            If ret.Matches = 1 Then

                'If there is exactly one match, we will set the text value of that item to the textbox, and  

                'populate the properties of the return value object    

                ret.TextboxValue = dt.Rows(0)("username").ToString()

                ret.DropDownHTML = "<div id=""dvSelectionList""></div>"

                ret.TextBoxID = dt.Rows(0)("userid")

                ret.Value1 = ""

                ret.Value2 = ""

            Else

                'If more than one match, we will show a scrollable div right below the textbox that lists

                'out all the matches.  The div will contain a table, that has events for mouseover, to show

                'that a row is selected, and onclick for the “td” tags to trigger an event that indicates the

                'clicked row has been selected

                sb.Append("<div id=""dvSelectionList"" style=""background-color:white;position:absolute;overflow:auto;width:353px;height:150px"">")

                sb.Append("<table cellpadding=0 cellspacing=0 style=""width:335px;border-right: #000000 1px solid;border-top: #000000 1px solid;border-left: #000000 1px solid;border-bottom: #000000 1px solid;"">")

 

                For i As Integer = 0 To dt.Rows.Count - 1

                    sb.Append("<tr><td id=""td" & i & """ width=240 " & _

                                "onclick=""document.all['txtInputBox'].value=document.all['td" & i & "'].innerText;UpdatePOS('" & dt.Rows(i)("UserName").ToString().Trim & "');"" " & _

                                "onmouseover=""this.className='SelectedRowItem'"" " & _

                                "onmouseout=""this.className='RowItem'""><font size=1>")

                    sb.Append(dt.Rows(i)("UserName").ToString())

                    sb.Append("</font></td></tr>")

                Next

                sb.Append("</table></div>")

                If dt.Rows.Count = 0 Then

                    ret.TextboxValue = Filter.Remove(Filter.Length - 1, 1)

                Else

                    ret.TextboxValue = Filter

                End If

                ret.DropDownHTML = sb.ToString()

            End If

        Else

            ret.TextboxValue = ""

            ret.Matches = 0

            ret.DropDownHTML = "<div id=""dvSelectionList""></div>"

        End If

 

        Return ret

    End Function

#End Region

 

 

Data Retrieval:

 

    Private Function GetFilteredData(ByVal filter As String) As DataTable

        Dim users As String = _

            "<users>" & _

            "<usertable><userid>1</userid><username>John Doe</username></usertable>" & _

            "<usertable><userid>2</userid><username>Jane Doe</username></usertable>" & _

            "<usertable><userid>3</userid><username>Ant Hill</username></usertable>" & _

            "<usertable><userid>4</userid><username>Ben Ten</username></usertable>" & _

            "<usertable><userid>5</userid><username>Craig List</username></usertable>" & _

            "<usertable><userid>6</userid><username>Godfrey Jones</username></usertable>" & _

            "<usertable><userid>7</userid><username>Tonya Roberts</username></usertable>" & _

            "</users>"

 

        Dim ds As New DataSet

        Dim xReader As System.IO.StringReader = New System.IO.StringReader(users)

        ds.ReadXml(xReader, XmlReadMode.Auto)

 

        Return ConvertDataRowArrayToDataTable(ds.Tables(0).Select(filter))

    End Function

 

    Public Function ConvertDataRowArrayToDataTable(ByVal drAry As DataRow(), _

Optional ByVal DistinctColumn As String = "") As DataTable

        Dim dt As New DataTable

        If drAry.Length > 0 Then

            Dim dr As DataRow

            Dim hshDistinct As New Hashtable

            Dim hshKey As String = ""

            For Each dc As DataColumn In drAry(0).Table.Columns

                dt.Columns.Add(dc.ColumnName, dc.DataType)

            Next

 

            For i As Integer = 0 To drAry.Length - 1

                dr = dt.NewRow

                For Each dc As DataColumn In drAry(i).Table.Columns

                    dr(dc.ColumnName) = drAry(i)(dc.ColumnName)

                Next

 

                If DistinctColumn <> "" Then

                    hshKey = dr(DistinctColumn).ToString()

                    If hshDistinct.Contains(hshKey) = False Then

                        dt.Rows.Add(dr)

                        hshDistinct.Add(hshKey, Nothing)

                    End If

                Else

                    dt.Rows.Add(dr)

                End If

            Next

        End If

        Return dt

    End Function

User Control (Ascx Page)

Since this is a user control, we will be creating the Tags on the ascx page that will represent the control objects we are manipulating in the code behind. Ideally, these controls could be generated dynamically from the codebehind, and placed dynamically on the users control page object.  For simplicity, however, we will be typing in the tags.

 

Controls:

We need to create the HTML Controls that the Auto-fill control will use. 

 

<input type=text id="txtInputBox" onkeyup="UpdatePOS(this.value)" style="Width:100px"/>       

<span id="btnClearInputBox" style="visibility:hidden;">

<a href="javascript:btnClearInputBox_Click();">clear</a>

</span>

<br />

<div id="dvSelectionList"></div>

<asp:Literal Runat=server ID="litScript"></asp:Literal>

<input type=hidden id="hdnInputBoxValue"/>

 

Script:

We need to manually define the supporting javascript code that the Auto-fill control will be using.  This can all be defined in the code behind as well.  For simplicity, we will leave them on the ascx file.

 

<script language="javascript">

    function UpdatePOS(filter)

    {  

        var pos = Autofill.UpdateDropdownList(filter).value;

        if(pos!=null)

        {

            if(pos.Matches==1)

            {

                document.all['txtInputBox'].value = pos.TextboxValue;

                document.all['txtInputBox'].disabled = true;

                document.all['hdnInputBoxValue'].value = pos.TextBoxID;

                document.all['dvSelectionList'].outerHTML = pos.DropDownHTML;

                document.all['btnClearInputBox'].style.visibility = "";

               

            }

            else

            {

                document.all['btnClearInputBox'].style.visibility = "hidden";

                if(pos.Matches==0)

                {

                    if(document.all['dvSelectionList'].innerHTML!="" && pos.TextboxValue!="")

                    {

                        UpdatePOS(pos.TextboxValue,eventid,keycode);

                    }

                    document.all['txtInputBox'].value = pos.TextboxValue;

                    document.all['hdnInputBoxValue'].value = pos.TextBoxID;

                }

                else

                {

                    document.all['dvSelectionList'].outerHTML = pos.DropDownHTML;

                    document.all['txtInputBox'].value = pos.TextboxValue;

                    document.all['hdnInputBoxValue'].value = pos.TextBoxID;

                }

            }

        }

    }

   

    function btnClearInputBox_Click()

    {

        if(document.all['txtInputBox'].disabled)

        {

            document.all['txtInputBox'].disabled = false;

            document.all['txtInputBox'].value = '';

            document.all['hdnInputBoxValue'].value = '';

            document.all['btnClearInputBox'].style.visibility = "hidden";

        }

    }  

 

</script>

Sample files:

The sample files are slightly different from the sample code above.  The code above will work, but will require some extra coding, for you to be able to add more than one instance of this control in your page.  If you use the sample, you should modify the database retrieval function “GetFilteredData” to retrieve the data that you want to query.  The sample files are built for use with Visual Studio 2005, however, the code would work in Visual Studio 2003 or earlier.  You will just need to get the AJAX.Net library for the earlier Visual Studio Versions.

Room for Improvement

There is always room for improvement with anything. 

 

It would be nice to be able to scroll through the items using the up and down arrow keys.  This needs to be thought through and coded in the future.

 

This control can be compiled as a server control, so that it can be deployed and used easily by other developers.  However, you will lose the flexibility that a user control (which is co-mingled with the rest of your code) can give you.

 

This solution may not be the best way to do this particular job, but it definitely works, and is meant to stir up ideas for your own implementation.  Please feel free to provide feedback on how this solution can be improved.

From:
http://www2.mybridgepoint.com/jgavilan/articles/156.aspx

Add by : Huobazi (2006-7-25:09:34)