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 FAQ 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:
Imports System Imports System.Collections
Then start on the class
Public Class YourClass: Implements IComparable
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)
Private _sErrorTitle As String Private _sDisplayText As String
Then add your ReadOnly Properties
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
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
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
Public Class YourClassCollection: Inherits CollectionBase
Then there are the standard instantiation/disposal methods
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
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
Public Sub Add(ByVal oObjectList As YourFirstClass) Me.InnerList.Add(oObjectList) End Sub
Next is the method to remove an item from the class
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
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
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.
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
Private oError As New amaPNRError '(name of my collection) Private oErrorList As ErrCollection '(Name of my collection)
Then use it like this
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.