EzBlog

Blogs from the mind of Tim Price

My Links

Blog Stats

Article Categories

Archives

Sorting & Filtering Custom Collections Part 2

Sorting and Filtering Custom Collections Part 2

By Tim Price

 

Requirements

 

Microsoft® Visual Studio® .NET 2003

Microsoft® Visual Basic .NET

 

Introduction

 

This is the second and final part in a series of articles explaining how to add Sorting & Filtering functionality to a custom collection of business objects. The custom objects were built in Part 1 of this article.

 

In this part we will walk through the process of creating a .Net Windows application that will expose the functionality to a user.

 

The Application

 

We will start by having a look at the finished application. Figure 1 is a screen shot of the application we will be building in this application.

 

 

Figure 1

 

The application contains a ‘Load Data’ button which simply loads a collection of Person objects and binds that collection to the datagrid, which is displayed in the bottom half of the above screenshot. The Reset button simply sets the datasource property of the datagrid to nothing. The Add button allows the user to add a new Person object to the collection.

 

The area entitled Sort allows the user to select the field they want to sort the collection in and the direction they want the collection sorting. The results are then re-binded to the datagrid

 

The Find area allows the user to enter a string value and select which field they want to do the search in.  The results are then re-binded to the datagrid.

 

Start by creating a new .Net Windows application. Rename the default form (Form1) to something a little more in memorable, I have chosen frmMain. Now open the code window for this form.

 

XML DataSource

 

We are going to use an xml document as our datasource for this example, obviously, you can use whatever datasource you want.

 

Have a look at the xml data schema below to see the how the data is stored in xml format.

xml version="1.0" encoding="utf-8" ?>

<Persons>

      <Person>

            <FirstName>TimFirstName>

            <LastName>PriceLastName>

            <Age>38Age>

      Person>

      <Person>

            <FirstName>DamianFirstName>

            <LastName>BarrowLastName>

            <Age>28Age>

      Person>

      <Person>

            <FirstName>RobFirstName>

            <LastName>FiskLastName>

            <Age>27Age>

      Person>

      <Person>

            <FirstName>PeterFirstName>

            <LastName>WilliamsLastName>

            <Age>25Age>

      Person>

      <Person>

            <FirstName>PaulFirstName>

            <LastName>StagemanLastName>

            <Age>26Age>

      Person>

Persons>

 

frmMain Design

 

Add the following objects to your form and arrange them similar to Figure 1, above.

 

Item

Name

Text

Enabled

 

 

Button

cmdLoadData

Load Data

True

Button

cmdReset

Reset

False

GroupBox

GroupBox1

Sort

 

RadioButton

radFirstname

Firstname

 

RadioButton

radLastname

Lastname

 

ComboBox

cboDirection

 

 

Button

cmdSort

Sort

False

RadioButton

radAge

Age

 

GroupBox

GroupBox2

Filter For

 

Label

Label1

Find what

 

TextBox

txtFind

 

 

Label

Label2

In what

 

ComboBox

cboInWhat

 

 

Button

cmdFilter

Filter

False

DataGrid

grdPersons

 

 

 

frmMain Code

 

Add the following line of code to the top of the file.

 

Imports System.Xml

 

We need this simply because we are going to load our person data from an xml file. You will need to replace this with whatever is the relevant namespace/s, for your data access method.

 

Locate the following line in the code window:

 

‘Windows Form Designer generated code’

 

And enter the following line of code.

 

Private m_oPersons As Persons

 

This variable will hold our modularly visible collection of Person objects.

 

We are going to add two structures to our form code that will enable us to define the text and values for the Sort Direction and Filter Field ComboBoxes. Note: Structures are out of the scope of this article, I will say however, that structures are similar to classes and can act as a datasource to bind able objects. For more information on structures, please refer to the ‘Further Reading’ section at the end of this article.

 

Add the following code to your class, just below the collection variable.

 

#Region "Structures"

 

    Structure SortDirections

 

        Private m_sText As String

        Private m_iValue As Integer

 

        Public Sub New(ByVal sText As String, ByVal iValue As Integer)

            m_sText = sText

            m_iValue = iValue

        End Sub

 

        Public ReadOnly Property DisplayText() As String

            Get

                Return m_sText

            End Get

        End Property

 

        Public ReadOnly Property Value() As Integer

            Get

                Return m_iValue

            End Get

        End Property

 

    End Structure

 

    Structure FilterFields

 

        Private m_sText As String

        Private m_sValue As String

 

        Public Sub New(ByVal sText As String, ByVal sValue As String)

            m_sText = sText

            m_sValue = sValue

        End Sub

 

        Public ReadOnly Property DisplayText() As String

            Get

                Return m_sText

            End Get

        End Property

 

        Public ReadOnly Property Value() As String

            Get

                Return m_sValue

            End Get

        End Property

 

    End Structure

 

#End Region

 

We now need to add code to the frmYOURNAME_Load event. This is the code we want to execute as and when the form loads and is where we will populate our two ComboBoxes with their text and value properties.

 

Add the following code to your forms load event.

 

Private Sub frmMain_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load

 

Dim oSortDirections() As SortDirections = {New SortDirections("ASC", 0), New SortDirections("DESC", 1)}

 

With cboDirection

.DataSource = oSortDirections

.DisplayMember = "DisplayText"

.ValueMember = "Value"

.SelectedIndex = 0

End With

 

Dim oFilterFields() As FilterFields = {New FilterFields("Firstname", "FIRSTNAME"), New FilterFields("Lastname", "LASTNAME"), New FilterFields("Age", "AGE")}

 

With cboInWhat

.DataSource = oFilterFields

.DisplayMember = "DisplayText"

      .ValueMember = "Value"

      .SelectedIndex = 0

End With

End Sub

 

We have created an array of SortDirection Structures and populated their DisplayText and Value properties with the values:

           

  • ASC – DisplayText
  • 0 – Value
  • DESC – DisplayText
  • 1 – Value

 

We have then taken this array and assigned them to the DataSource property of the cboDirection ComboBox, we have set the DisplayMember property of the ComboBox equal to the DisplayText if the structure, this is what the user sees as the text for the control, we then set the ValueMember property of the control to the Value property of the Structure. Finally we tell the ComboBox that the SelectedIndex property is 0. This makes the control display the first item in it’s collection of values and text properties.

 

We then repeat the process again, but this time use the FilterFields structure and the cboInWhat control.

 

That’s all we need to do for the Load event of the form, so let’s move onto actually loading the data and populating our collection.

 

cmdLoadData_Click

 

Double click the cmdLoadData button on the forms designer to have Visual Studio open the code editor with the buttons click event code in place and add the following code.

 

    Private Sub cmdLoadData_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdLoadData.Click

        Try

            Dim sPath As String = Application.StartupPath

 

            If sPath.EndsWith("bin") Then

                sPath = sPath.Remove((sPath.Length - 3), 3)

            End If

 

            Dim oDOM As New XmlDocument

            Try

                oDOM.Load(sPath & "Persons.xml")

            Catch ex As XmlException

                Throw New Exception(ex.Message)

            End Try

            m_oPersons = New Persons(oDOM)

            With grdPersons

                .DataMember = "Persons"

                .DataSource = m_oPersons

            End With

            ButtonsEnabled()

        Catch ex As Exception

            Throw New Exception(ex.Message, ex.InnerException)

        End Try

    End Sub

 

Within this routine we create a variable of type string to hold the path to our xml document, in this case the xml document is stored in the applications bin directory, you will need to alter this to match your path, if you decide to store your file in a different location.

 

Once we have the correct path we need to create a variable of type XmlDocument, we then need to load the xml file into the document. We then pass this new xml document to the new constructor of the Persons class, to have the collection populated with the xml data.

 

Now that we have a collection of Persons we simply tell our DataGrid what the DataMember property is and set it’s DataSource equal to our Persons collection.

 

Finally we call a private sub-routine ButtonsEnabled.

 

ButtonsEnabled

 

Private Sub ButtonsEnabled()

    cmdLoadData.Enabled = Not cmdLoadData.Enabled

    cmdClear.Enabled = Not cmdClear.Enabled

    cmdSort.Enabled = Not cmdSort.Enabled

    cmdFilter.Enabled = Not cmdFilter.Enabled

End Sub

 

Nothing will be said about this routine, it should be pretty obvious what is going on.

 

cmdClear_Click

 

We are now going to add the code to the click routine of our Clear button, so either double click the clear button in the form designer, or locate the cmdClear button in the Class Name dropdown at the top left of the code editor window and the click event from the Method Name drop down at the top right hand side of the code editor window.

 

Once Visual Studio puts the basic click event code in place add the following code to create the clear functionality.

 

Private Sub cmdClear_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdClear.Click

 

grdPersons.DataSource = Nothing

      ButtonsEnabled()

      txtFind.Text = String.Empty

End Sub

 

Again, nothing further will be said about this code, it should be pretty obvious exactly what is going on here.

 

cmdSort_Click

 

Bring up the skeleton code for the cmdSort click event and enter the following code.

 

Private Sub cmdSort_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSort.Click

 

Try

          If radFirstname.Checked Then

              m_oPersons.Sort("firstname", cboDirection.SelectedValue)

          ElseIf radLastname.Checked Then

              m_oPersons.Sort("lastname", cboDirection.SelectedValue)

          ElseIf radAge.Checked Then

              m_oPersons.Sort("age", cboDirection.SelectedValue)