In the application I'm currently working on it involves communicating with a host application. If an error occurs, the host can send back one of about 60 error messages (depending). I needed a way to check the host response after entries. I didn't want to do an if loop through all 60 error messages so I came up with the idea of taking the error messages and putting them into a delimited file ( used "!" as my delimiter as some of the error messages had "," in them).
The earlier [link http://tek-tips.com/faqs.cfm?fid=6542]FAQ[/link] showed how I read the delimited file into an XML document, this one will show how to take the elements and put them into a collection for ease of use. First Ill do the actually Collection (it's actually 2 classes in one).
In the collection files first make sure to import the right namespaces:
Code:
Imports System
Imports System.Collections
Then start on the class
Code:
Public Class YourClass: [b]Implements IComparable[/b]
Make sure to add the
bold text, its important within the class. Next you declare your Property variables (my xml document only has 2, you can have as many as your xml document has)
Code:
Private _sErrorTitle As String
Private _sDisplayText As String
Then add your
ReadOnly Properties
Code:
Public ReadOnly Property ErrorTitle() As String
Get
Return _sErrorTitle
End Get
End Property
Public ReadOnly Property DisplayText() As String
Get
Return _sDisplayText
End Get
End Property
The properties can be names what you want them named (and if you're working with an XML document with more than 2 elements then make as many properties as you have elements). Next comes the instantiation and disposal of the class
Code:
Public Sub New(ByVal sErrTitle As String, ByVal sDisplayTxt As String)
Me._sErrorTitle = sErrTitle
Me._sDisplayText = sDisplayTxt
End Sub
Public Sub Dispose()
Me.Dispose()
End Sub
Next, when you create a collection class that inherits IComparable you
have to have a
CompareTo function
Code:
Public Function CompareTo(ByVal obj As Object) As Integer Implements IComparable.CompareTo
'Check to see if obj is actually your collection class
If Not (TypeOf obj Is YourCollection) Then
'If not throw an exception
Throw New ArgumentException
End If
Dim oObject As YourCollection = CType(obj, YourCollection)
Dim cmpl As Integer = Me.ErrorTitle.CompareTo(oObject.YourCollection)
If Not (cmpl = 0) Then
Return cmpl
End If
Return Me.YourPropertyName.CompareTo(oOBject.YourPropertyName)
End Function
That is the function that implements IComparable, the second class uses the items in this class, but it inherits
CollectionBase, doing this makes several methods available to collections not inheriting it. First name your class
Code:
Public Class YourClassCollection: Inherits CollectionBase
Then there are the standard instantiation/disposal methods
Code:
Public Sub New()
End Sub
Public Sub Dispose()
Me.Dispose()
End Sub
First is the property, this is what you will be calling when you go to add the XML items into the collection
Code:
Default Public Property ErrorItems(ByVal idx As Integer) As FirstClassName
Get
'idx is the integer value of the index you are working with
Return CType(Me.InnerList(idx), FirstClassName)
End Get
Set(ByVal value As FirstClassName)
Me.InnerList(idx) = value
End Set
End Property
Next are the methods that open up to you when you inherit from
CollectionBase. First is the
Add Method which adds the item to the collection
Code:
Public Sub Add(ByVal oObjectList As YourFirstClass)
Me.InnerList.Add(oObjectList)
End Sub
Next is the method to remove an item from the class
Code:
Public Sub Remove(ByVal oObjectList As YourFirstClass)
If Not Me.Contains(oObjectList) Then
Exit Sub
End If
Dim iCount As Integer = 0
While iCount < Me.InnerList.Count
Dim oNewObjectList As YourFirstClass = CType(Me.InnerList(iCount), oObjectList)
If oNewObjectList.CompareTo(oObjectList) = 0 Then
Me.RemoveAt(iCount)
Exit Sub
End If
System.Math.Min(System.Threading.Interlocked.Increment(iCount), iCount - 1)
End While
End Sub
This function searches the collection looking for the requested item, if its found then it removes it from the collection.
The next method is the
Contains method. This method is used in conjunction with the
Remove method, when adding items to the collection I call this to see if the item already exists, if it does then I either call
Removeto remove it then re add it, or I simply skip the item. The last method opened to you is the ability to turn the collection into an Array
Code:
Public Function ToArray() As YourFirstClass()
Return CType(Me.InnerList.ToArray(GetType(YourFirstClass)), YourFirstClass())
End Function
Like I said, I made both class file in one. Now to read the XML doxument and add it to your new collection I used the following function. First create your 2 new class file in objects
Code:
Private oErrorList As FirstClass
Private oError As New ClassCollection
Then simply read the XML document and add to the collection. This function I have in a completely seperate class file, you can do it however you want, I personally prefer the use of Class files to seperate code.
Code:
Public Function GetList(ByVal sFile As String, ByVal sFileName As String, _
ByVal sTagName As String) As ErrCollection
'Check to make sure document exists
If Not File.Exists(sFile.TrimEnd) Then 'Document doesnt exist
'Write to error log
oEvents.WriteToLog(sFileName.TrimEnd & ".xml file not found.", "", sFileName.TrimEnd & ".xml Not Found.")
'Let the user knwo the problem
MsgBox("The text file could not be found." & vbCrLf & _
"Please contact your software support", MsgBoxStyle.Critical)
'Exit the function
Return Nothing
Exit Function
Else
'Open the XML document
xmlDoc.Load(sFile.TrimEnd)
Try
xmlDocNode = xmlDoc.GetElementsByTagName(sTagName.TrimEnd)
'Loop through all the nodes in the xml document
For Each xmlNewNode As Xml.XmlNode In xmlDocNode
'Create new collection object with the element values of the xml document
oErrorList = New ErrorList(xmlNewNode.Attributes("ErrorTitle").InnerText.TrimEnd, _
xmlNewNode.Attributes("DisplayText").InnerText.TrimEnd)
'Check to see if it already exists in the Collection
If Not oError.Contains(oErrorList) Then 'Doesnt contain
'So add it
oError.Add(oErrorList)
Else 'Contains this element already
'So remove it
oError.Remove(oErrorList)
End If
Next 'xmlNewNode
GetList = oError
Return GetList
Catch ex As Exception 'An Exception occurred
'Log the exception
oEvents.WriteToLog(ex.Message, ex.StackTrace, "ConvertXMLToCollection Error")
'Let the user know there was a problem
MsgBox("The XML Document could not be converted." & vbCrLf & _
"Please contact your software support", MsgBoxStyle.Critical)
'Exit the function
Return Nothing
Exit Function
Finally 'Do this no matter what
'Dispose of the objects
oErrorList.Dispose()
oError.Dispose()
sFile = String.Empty
sFileName = String.Empty
sTagName = String.Empty
End Try
End If
End Function
ErrorTitle and
DisplayText are the name of my elements, you replace this with your own element names.
oError and
oErrorList are the names of my 2 objects, depending on what you name your classes replace these names with yours.
Now in the form's .vb file where I need to get the collection I do as follows,
first instantiate your objects
Code:
Private oError As New amaPNRError '(name of my collection)
Private oErrorList As ErrCollection '(Name of my collection)
Then use it like this
Code:
oErrorList = oError.GetList(Application.StartupPath & "\LoginErrorList.xml", "LoginErrorList", "ErrorList")
For iCount As Integer = 0 To oErrorList.Count - 1
If Not ItHasErrors(oHost.LastResponse.Text, oErrorList.ErrorItems(iCount).ErrorTitle) = True Then 'No errors
_sErrMessage = EnumToText(9)
_bProcessComplete = True
_bHasErrors = False
Else
_sErrMessage = oErrorList.ErrorItems(iCount).ErrorTitle
_bProcessComplete = True
_bHasErrors = True
Exit Sub
End If
Next
In this code there are things that are specific to my application, but it grabs the error list collection and I loop through it looking for anything that matches the response from the host, if one matches then I have an error so I need to set my error properties to true and exit the procedure.
I hope this helps someone in the future, I have ran my own tests and this approach seems to work faster then searching the document when I need to check for hours.