How can I use textbox textchanged events to change user input classes? - vb.net

InputValue1,..OperationAdd are instances of the class InputNumber. How do I assign my Inputvalues to the corresponding textboxes as option Strict On is activated?
Class MainWindow
Dim InputValue1 As New InputNumber
Dim InputValue2 As New InputNumber
Dim ExpectedResultValue As New InputNumber
Dim OperationAdd As New InputNumber
Private Sub TBoxNumber1_TextChanged(sender As Object, e As TextChangedEventArgs) Handles TBoxNumber1.TextChanged
TBoxNumber1.Text = InputValue1 'There is an error in this line, value of type InputNumber 'cannot be converted to a string
End Sub
Below is the InputNumber Class:
Public Class InputNumber
Inherits Input
Private _number As Integer
Public Property Number As Integer
Get
Return _number
End Get
Set(value As Integer)
_number = value
End Set
End Property
Protected Overrides Function Validate(s As String) As Boolean
Dim isValid As Boolean = Integer.TryParse(s, _number)
Return isValid
End Function
End Class

It seems to me that you should be getting the input from the TextBox into your InputNumber object, not the other way around. This:
TBoxNumber1.Text = InputValue1
should probably be this:
InputValue1.Validate(TBoxNumber1.Text)
When it actually comes time to display the value of that InputNumber, you would have to use InputValue1.Number.ToString(). Personally, I would add this to your InputNumber class:
Public Overrides Function ToString() As String
Return Number.ToString()
End Function
and then you can use InputValue1.ToString() instead.
EDIT:
It's been pointed out that the Validate method is Protected so it can't be called like that. Unless there's some use for it in the Input base class, I'm not sure what it's for because, as it stands, you'd need to validate externally anyway, e.g.
Dim number As Integer
If Integer.TryParse(TBoxNumber1.Text, number) Then
InputValue1.Number = number
End If

I am questioning the implementation of InputNumber. It does not make much sense in the current form. We don't know when validation is happen and Number is integer in fact.
I would do something like this.
Public Class InputNumber
Private _number As Integer
Private _hasNumber As Boolean
Public Sub New(s As String)
SetNumber(s)
End Sub
Public Sub New()
End Sub
Public ReadOnly Property Number As Integer
Get
Return _number
End Get
End Property
Public ReadOnly Property HasNumber As Boolean
Get
Return _hasNumber
End Get
End Property
Public Sub SetNumber(s As String)
_hasNumber = Integer.TryParse(s, _number)
End Sub
' For consistency...
Public Sub SetNumber(i As Integer)
_hasNumber = true
_number = i
End Sub
Public Overrides Function ToString() As String
If HasNumber Then Return Number.ToString()
Return String.Empty
End Function
End Class
Then your usage will be (and I agree with #jmcilhinney, when you have TextChange event, you want to take a value from the text box and set a variable)
Dim inp As New InputNumber("ddd")
txtBox1.Text = If(inp.HasNumber, inp.Number.ToString(), "NO VALUE") '' example to use HasNumber
inp.SetNumber("sss")
txtBox2.Text = inp.ToString() '' Example to use straight value
inp.SetNumber(10)
Dim current As Integer = If(inp.HasNumber, inp.Number, -1) '' using as numeric value
Now, this class makes slightly more sense

Related

Overriding Sub to check if value is numeric

I'm working on a problem with two user input controls, TextInput and NumericInput. TextInput accepts all characters, whereas NumericInput only accepts numeric inputs.
I'm aware that for my NumericInput Add Sub I will probably have to create a boolean to check if the input value is a number or not and then create an If statement using the boolean, however, I'm not sure how to go about this.
This is the code that I was able to come up with.
For my TextInput code I currently have the following:
Dim value As String 'current value'
Public Class TextInput
Public Overridable Sub Add(c As Char)
If value.length = 0 Then
value = Char.toString(c)
Else
value+=c
End If
End Sub
Public Function GetValue() As String
Return value
End Function
End Class
For my NumericInput code I currently have the following:
Public Class NumericInput
Inherits TextInput
Dim numericCheck As Boolean
Public Overrides Sub Add(c As Char)
If Not value.length = 0 Then
numericCheck = isNumeric(value)
End If
If numericCheck = True Then
value+=c
End If
End Sub
End Class
Output code is as follows:
Public Sub Main()
Dim input As TextInput = New NumericInput()
input.Add(CChar("1"))
input.Add(CChar("a"))
input.Add(CChar("0"))
Console.WriteLine(input.GetValue())
End Sub
First, the variable value should be encapsulated in TextInput class. You can declare it as protected so derived classes can access it. The value variable must have initial value otherwise value.Length raises an exception because it's null (Nothing).
Secondly, you can use IsNumeric function to check if a character is a number. Then call the base method of Add if it's a number.
Public Class TextInput
Protected value As String = "" 'current value'
Public Overridable Sub Add(c As Char)
If value.Length = 0 Then
value = Char.toString(c)
Else
value += c
End If
End Sub
Public Function GetValue() As String
Return value
End Function
End Class
Public Class NumericInput
Inherits TextInput
Public Overrides Sub Add(c As Char)
If IsNumeric(c) Then
MyBase.Add(c)
End If
End Sub
End Class

How to support contextual implicit conversions of custom object in Visual Basic .NET?

I want to use named error codes within my app. This should ensure, that every developer does not confuse numeric-only error codes with other codes, and also reduces the time a developer needs to realize what the error code should represent.
Compare this example:
Function New() As Integer
Return 0
End Function
with this example:
Function New() As Integer
Return ErrorCodes.ERROR_SUCCESS
End Function
Of course, I could let the developers write like the following:
Function New() As Integer
Return 0 ' ERROR_SUCCESS
End Function
However, the code above raises a pitfall when a developer updates the actual return code but forgets about the comment. Some developer look at the actual return code and some at the comment. I want to mitigate that confusion.
I come up the following class (extract):
Public Class ErrorCodes
Private msName As String = Nothing
Private miValue As Integer = 0
Public Shared ReadOnly ERROR_SUCCESS As ErrorCodes = New ErrorCodes("ERROR_SUCCESS", 0)
Private Sub New(ByVal psName As String, ByVal piValue As Integer)
msName = psName
miValue = piValue
End Sub
Public ReadOnly Property [Name] As String
Get
Return msName
End Get
End Property
Public ReadOnly Property [Value] As Integer
Get
Return miValue
End Get
End Property
Public Overrides Function ToString() As String
Return String.Format("[{0}]{1}", msName, miValue)
End Function
End Class
Now I want to use this ErrorCodes class like in the following example:
Function New() As Integer
Return ErrorCodes.ERROR_SUCCESS
End Function
As expected, I will produce an exception (type conversion) since the actual value I return is a instance of the class ErrorCodes instead of the generic data type Integer.
As you can see with the ToString() function, I let the class automatically/implicitly converts the instanced object into the generic data type String, when the class instance is assigned to a String typed variable.
Is there a way to do the same with the generic data type Integer like I did with ToString()?
I am using the .NET Framework 4.0, as for compatibility reasons with Windows XP SP3.
Another way to say what I want:
Dim stringVariable As String = ErrorCodes.ERROR_SUCCESS ' should be "[0]ERROR_SUCCESS".
Dim integerVariable As Integer = ErrorCodes.ERROR_SUCCESS ' should be 0.
I do not want to trigger implicit conversion warnings/errors, or to force the developer to typecast explicitly.
Yes you can do that with the use of Conversion Operators.
Here is the code:
Public Class Form1
Public Class ErrorCodes
Private msName As String = Nothing
Private miValue As Integer = 0
Public Shared Widening Operator CType(ByVal ec As ErrorCodes) As String
Return ec.ToString
End Operator
Public Shared Narrowing Operator CType(ByVal ec As ErrorCodes) As Integer
Return ec.Value
End Operator
Public Shared ReadOnly ERROR_SUCCESS As ErrorCodes = New ErrorCodes("ERROR_SUCCESS", 0)
Public Shared ReadOnly ERROR_FAILED As ErrorCodes = New ErrorCodes("ERROR_FAILED", 1)
Private Sub New(ByVal psName As String, ByVal piValue As Integer)
msName = psName
miValue = piValue
End Sub
Public ReadOnly Property [Name] As String
Get
Return msName
End Get
End Property
Public ReadOnly Property [Value] As Integer
Get
Return miValue
End Get
End Property
Public Overrides Function ToString() As String
Return String.Format("[{0}]{1}", msName, miValue)
End Function
End Class
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim em As String = ErrorCodes.ERROR_SUCCESS
Dim ev As Integer = ErrorCodes.ERROR_SUCCESS
Dim mm As String = String.Format("String: {0}, Value: {1}", em, ev)
MsgBox(mm)
End Sub
End Class
More info here
Hope this helps.
This, as jmcilhinney pointed out, uses Enums and the Description attribute.
Here is the class
'requires
' Imports System.Reflection
' Imports System.ComponentModel
Public Class ErrorCodes
Public Enum ErrCode 'these are the error codes
'note that the codes should be unique
<Description("Success")> ERROR_SUCCESS = 0
<Description("Error A")> ERROR_A = 1
End Enum
Public Class InfoForErrCode
Public TheDescription As String
Public TheValue As Integer
Public AsString As String
End Class
Public Shared Function Info(TheError As ErrCode) As InfoForErrCode
Dim rv As New InfoForErrCode
rv.TheDescription = GetDescription(TheError)
rv.TheValue = TheError
rv.AsString = TheError.ToString
Return rv
End Function
Private Shared Function GetDescription(TheError As ErrCode) As String
Dim rv As String = ""
Dim fi As FieldInfo = TheError.GetType().GetField(TheError.ToString())
Dim attr() As DescriptionAttribute
attr = DirectCast(fi.GetCustomAttributes(GetType(DescriptionAttribute),
False), DescriptionAttribute())
If attr.Length > 0 Then
rv = attr(0).Description
Else
rv = TheError.ToString()
End If
Return rv
End Function
End Class
And here is how it can be used
Dim foo As ErrorCodes.ErrCode = ErrorCodes.ErrCode.ERROR_SUCCESS
Dim inf As ErrorCodes.InfoForErrCode = ErrorCodes.Info(foo)
Stop 'examine inf
foo = ErrorCodes.ErrCode.ERROR_A
inf = ErrorCodes.Info(foo)
Stop 'examine inf

Comparing list of class by string length and text comparison

I have a List(Of Abbreviation).
The class "Abbreviation" contains the string members "Input", "Output" and "CaseSensitive".
The class is stated below.
I would like to sort this list so that the class with the "Input"
"ZZZ"
comes before
"zz"
The comparison should thus first compare by string length, then by alphetical order, and then by CaseSensitive.
How could I sort the list this way?
Public Class Abbreviation
Implements IComparable
Private _sIn As String = String.Empty
Private _sOut As String = String.Empty
Private _bCaseSensitive As Boolean = False
Public Property Input() As String
Get
Return _sIn
End Get
Set(value As String)
_sIn = value
End Set
End Property
Public Property Output() As String
Get
Return _sOut
End Get
Set(value As String)
_sOut = value
End Set
End Property
Public Property CaseSensitive() As Boolean
Get
Return _bCaseSensitive
End Get
Set(value As Boolean)
_bCaseSensitive = value
End Set
End Property
Public Sub New(ByVal uInput As String, ByVal uOutput As String, ByVal uCaseSensitive As Boolean)
_sIn = uInput
_sOut = uOutput
_bCaseSensitive = uCaseSensitive
End Sub
End Class
First, you can simplify your code by using automatic properties. The compiler writes the get, set, and backer fields (the private fields). This is the preferred way in recent versions of Visual Studio if there is no extra code in the getter, setter.
Another small detail with your Sub New. It violates encapsulation to set the private fields directly. Always go through the Public Properties. There could be code in the setter that needs to run before storing the data in the private fields. Classes like to keep their data close to the vest in their private fields.
Example of Auto Implemented Properties
Public Property Input As String
Public Property Output As String
Public Property CaseSensitive As Boolean
The sort can be done in one line of code using a Linq query.
Dim orderedList = From abrev In lstAbreviations Order By abrev.Input.Lenght Descending Select abrev
To check the output...
For Each abrev As Player In orderedList
Debug.Print(abrev.Input)
Next
I think I got it, except the case sensitivity. CaseSensitive should come before CaseSensitive = False.
Public Class Abbreviation
Implements IComparable(Of Abbreviation)
Private _sIn As String = String.Empty
Private _sOut As String = String.Empty
Private _bCaseSensitive As Boolean = False
Public Function CompareTo(uOther As Abbreviation) As Integer _
Implements IComparable(Of Abbreviation).CompareTo
If uOther.Input.Length > Me.Input.Length Then
Return 1
ElseIf uOther.Input.Length < Me.Input.Length Then
Return -1
Else
If uOther.Input > Me.Input Then
Return 1
Else
Return -1
End If
End If
End Function

VB .Net - ShouldSerialize function

I have a problem with ShouldSerialize function.
I defined an usercontrol with a label (named Label1) on it.
Now i put the code below in the usercontrol class :
Imports System.ComponentModel
Public Class UserControl1
Dim _Range As UShort = 100
Private Sub UserControl1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Label1.Text = _Range
End Sub
Public Function ShouldSerializeTBValueRange() As Boolean
Return _Range <> 200
End Function
Public Sub ResetTBValueRange()
_Range = 200
Label1.Text = _Range
End Sub
Public Property TBValueRange As UShort
Get
Return _Range
End Get
Set(ByVal Steps As UShort)
_Range = Steps
Label1.Text = _Range
End Set
End Property
End Class
Now in a new form include the usercontrol.
In the properties grid of the usercontrol u can find the property TBValueRange.
If you right click in the property name you can Reinit the property.
After reinit u can see value 200 in the property.
Now, regenerate the project will reset the property to the initial value (id 100).
Why the value 200 didn't stay?
If i replace the line Return _Range <> 200 in the function ShouldSerializeTBValueRange() by
Return Not _Range.Equals(200)
it will work.
i don't understand.
Anyone could explain this?
The methods are working as coded. The thing which seems to not work as expected is the Not _Range.Equals(200) portion.
You initialize _Range to 100: Dim _Range As UShort = 100
Then, your ShouldSerializeTBValueRange method tells VS to only save the range value when it is not 200: Return _Range <> 200
So, when you reset it to 200 in the IDE, it wont save a value of 200, and the initial value of 100 displays.
The code uses one value for the default, 100 but use a different value for ShouldSerialize test. You should either change it to use a default of 200:
Dim _Range As UShort = 200
Or change the ShouldSerialize test to use 100:
Public Function ShouldSerializeTBValueRange() As Boolean
Return _Range <> 100
End Function
Treating the default value as the default, and using only one value for the default everything works as expected using just ShouldSerializexxx and Resetxxx with no need for anything else.
' THIS is the default value -
' ie the value that need not be saved because the
' control automatically starts with that value
Dim _Range As UShort = 200US
' Controls:
' - displays the prop value in Bold in the property window
' when the value is NOT the default
' - saves the value when it is NOT the default
' - enables/disables the RESET function
Public Function ShouldSerializeTBValueRange() As Boolean
Return (_Range <> 200US)
End Function
Using one value for the actual default (100) and then returning T/F based on a different value (200) results in
100 being saved when it need not be
200 not being saved when it should be
the Reset menu item and Bold value being in the incorrect state
The oddity is that Not _Range.Equals(200) seems to fail. It returns False after a reset (to 200) which causes the value to be saved when it really should not. There are 2 overloads for this:
UInt16.Equals(obj As Object) As Boolean
UInt16.Equals(v As UShort) As Boolean
If you pass anything other than an actual UInt16/UShort, the value will be boxed as Object. So, Not _Range.Equals(200) is using the first because 200 is Int32. The ILCode for that version is:
public override bool Equals(object obj)
{
return obj is ushort && this == (ushort)obj;
}
The test will fail the first test because obj contains an Int32. If you pass a UShort, it will work:
UShort.Equals(_Range, 200US)
'or:
_Range.Equals(200US)
All good reasons to understand the different data types, avoid boxing (As Object) and always and forever set Option Strict On.
Thanks you all to have spent time on my question.
I found my answer : when ShouldSerialize function return false the property value isn't save in the file Form1.designer.vb, so it gets the original value.
For my needed the ShouldSerialize function should always return true.
Public Function ShouldSerializeTBValueRange() As Boolean
Return true
End Function
So the property value will always be saved.
Now, what i'm looking for is how to control the context menu of the property grid.
I want the option "Reinit" greyed when the value is good.
Finally, i found something, with the use of PropertyDescriptor.
For whose are interested, we can save properties in the designer.vb file and test the value to reset.
here is my program, based on the article from MSDN - Microsft:
Imports System.ComponentModel
Imports System.Windows.Forms.Design
<Designer(GetType(DemoControlDesigner))>
Public Class UserControl1
Dim _MyProperty1 As String = "Test1"
Dim _MyProperty2 As Integer = 100
Dim _MyProperty3 As UShort = 200
Public Sub New()
InitializeComponent()
End Sub
Public Function CanResetMyProperty1() As Boolean
Return _MyProperty1 <> "Test"
End Function
Public Sub ResetMyProperty1()
_MyProperty1 = "Test"
End Sub
Public Property MyProperty1 As String
Get
Return _MyProperty1
End Get
Set(ByVal Value As String)
_MyProperty1 = Value
End Set
End Property
Public Function CanResetMyProperty2() As Boolean
Return _MyProperty2 <> 150
End Function
Public Sub ResetMyProperty2()
_MyProperty2 = 150
End Sub
Public Property MyProperty2 As Integer
Get
Return _MyProperty2
End Get
Set(ByVal Value As Integer)
_MyProperty2 = Value
End Set
End Property
Public Function CanResetMyProperty3() As Boolean
Return _MyProperty3 <> _MyProperty2
End Function
Public Sub ResetMyProperty3()
_MyProperty3 = _MyProperty2
End Sub
Public Property MyProperty3 As UShort
Get
Return _MyProperty3
End Get
Set(ByVal Value As UShort)
_MyProperty3 = Value
End Set
End Property
End Class
Friend NotInheritable Class SerializePropertyDescriptor
Inherits PropertyDescriptor
Private _pd As PropertyDescriptor = Nothing
Public Sub New(ByVal pd As PropertyDescriptor)
MyBase.New(pd)
_pd = pd
End Sub
Public Overrides ReadOnly Property Attributes() As AttributeCollection
Get
Return Me._pd.Attributes
End Get
End Property
Protected Overrides Sub FillAttributes(ByVal attributeList As IList)
MyBase.FillAttributes(attributeList)
End Sub
Public Overrides ReadOnly Property ComponentType() As Type
Get
Return Me._pd.ComponentType
End Get
End Property
Public Overrides ReadOnly Property Converter() As TypeConverter
Get
Return Me._pd.Converter
End Get
End Property
Public Overrides Function GetEditor(ByVal editorBaseType As Type) As Object
Return Me._pd.GetEditor(editorBaseType)
End Function
Public Overrides ReadOnly Property IsReadOnly() As Boolean
Get
Return Me._pd.IsReadOnly
End Get
End Property
Public Overrides ReadOnly Property PropertyType() As Type
Get
Return Me._pd.PropertyType
End Get
End Property
Public Overrides Function CanResetValue(ByVal component As Object) As Boolean
Try
Return CallByName(component, "CanReset" & _pd.Name, CallType.Get, Nothing)
Catch ex As Exception
MsgBox(ex.Message)
End Try
Return False
End Function
Public Overrides Function GetValue(ByVal component As Object) As Object
Return Me._pd.GetValue(component)
End Function
Public Overrides Sub ResetValue(ByVal component As Object)
Me._pd.ResetValue(component)
End Sub
Public Overrides Sub SetValue(ByVal component As Object, ByVal val As Object)
Me._pd.SetValue(component, val)
End Sub
Public Overrides Function ShouldSerializeValue(ByVal component As Object) As Boolean
Return True
End Function
End Class
Class DemoControlDesigner
Inherits ControlDesigner
Dim PropertiesToSerialize As String() = {"MyProperty1", "MyProperty2", "MyProperty3"}
Protected Overrides Sub PostFilterProperties(ByVal properties As IDictionary)
Dim original As PropertyDescriptor
For Each PropName As String In PropertiesToSerialize
If properties.Contains(PropName) Then
original = properties(PropName)
properties(PropName) = New SerializePropertyDescriptor(original)
End If
Next
MyBase.PostFilterProperties(properties)
End Sub
End Class
For each property that should be serialized and tested for reset, we should write a sub "CanResetPropertyName" which test the value to reset (see sample).
And the values stay now, even if we regenerate the project.
It's working fine for me, maybe it can be improved.
Regards.

Populating a combo box with a list of functions - Need Advice

I'm looking for some advice on the best way to handle this.
I have a list of about 200 "Functions" which are listed in a combo box. When the user selects a 'function' from the list, I need to return the functionID (integer).
I know this can be done easily by binding a dataset to the key and value of the combobox, I'm just not sure about the best way to populate the dataset.
I feel that the way I'm doing it currently is very convoluted:
I currently have a txt file as an embedded resource which I write to a temporary directory, then I use the following code to read in that text file and populate that box by setting the combobox's datasource and Display Member. It does this by way of a custom class which is implementing System.Collections.IList.
I have pasted the code below. The reason I want to simplify it is that I dislike writing the text file to the disk, because sometimes it fails.
I'm looking for a way to populate my combobox and return my ID, without writing anything to the user's temp folder.
I am open to changing the format of the embedded resource, and or the code.
The fnlist.txt is formatted currently as follows.
index, Function Name, ID
The index is only included for sorting (to keep NONE at the bottom, and unknown function at the top), and I suppose is not strictly required.
#Region "Function lookup"
Dim path As String = System.IO.Path.GetTempPath
Dim _objFnXtef As New clsFunctionXref(path & "fnList.txt")
Private Sub populate_list()
functionlist.DataSource = _objFnXtef
functionlist.DisplayMember = "StrFunction"
End Sub 'Populates the function list
Function get_index(ByVal fnid As Integer)
Dim iLookupNumber As Integer = fnid
Dim tmpFnInfo As New clsFunctionInfo
Dim iReturnIdx As Integer = -1
If iLookupNumber <> 0 Then
tmpFnInfo.IFunctionNumber = iLookupNumber
iReturnIdx = _objFnXtef.IndexOf(tmpFnInfo)
If iReturnIdx <> -1 Then
Return iReturnIdx - 1
Else
Return get_index(9999)
End If
End If
Return 0
End Function 'Returns index of specified function number
#End Region 'All function list functions
Here is the code when a user changes the drop down:
Private Sub functionlist_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles functionlist.SelectedIndexChanged
Dim iReturnFuctionID As Integer = 0
Dim tmpFnInfo As New clsFunctionInfo
tmpFnInfo = _objFnXtef(functionlist.SelectedIndex)
iReturnFuctionID = tmpFnInfo.IFunctionNumber
Func = (iReturnFuctionID)
End Sub
And here is the supporting class:
Imports Microsoft.VisualBasic.FileIO
Public Class clsFunctionInfo
Private _idxFunction As Integer
Public Property IdxFunction() As Integer
Get
Return _idxFunction
End Get
Set(ByVal value As Integer)
_idxFunction = value
End Set
End Property
Private _strFunction As String
Public Property StrFunction() As String
Get
Return _strFunction
End Get
Set(ByVal value As String)
_strFunction = value
End Set
End Property
Private _iFunctionNumber As Integer
Public Property IFunctionNumber() As Integer
Get
Return _iFunctionNumber
End Get
Set(ByVal value As Integer)
_iFunctionNumber = value
End Set
End Property
End Class
Public Class clsFunctionXref
Implements System.Collections.IList
Private _colFunctionInfo As New Collection
Private _filePath As String
Public Property FilePath() As String
Get
Return _filePath
End Get
Set(ByVal value As String)
_filePath = value
End Set
End Property
Public Sub New(ByVal filename As String)
_filePath = filename
Dim _idx As Integer = 1
Dim fields As String()
Dim delimiter As String = ","
Dim iFnx As Integer
Using parser As New TextFieldParser(filename)
parser.SetDelimiters(delimiter)
While Not parser.EndOfData
' Read in the fields for the current line
fields = parser.ReadFields()
Try
iFnx = Convert.ToInt16(fields(0).ToString)
Catch ex As Exception
MessageBox.Show("Error reading file. " & ex.ToString, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Exit Sub
End Try
Dim objFunction As New clsFunctionInfo
objFunction.IdxFunction = _idx
objFunction.IFunctionNumber = iFnx
objFunction.StrFunction = fields(1).ToString
Me.Add(objFunction)
_idx += 1
End While
End Using
End Sub
Public Function Add(ByVal value As Object) As Integer Implements System.Collections.IList.Add
If _colFunctionInfo.Contains(value.IFunctionNumber.ToString) Then
SyncLock Me.SyncRoot
_colFunctionInfo.Remove(value.IFunctionNumber.ToString)
End SyncLock
ReIndex()
End If
SyncLock Me.SyncRoot
_colFunctionInfo.Add(value, value.IFunctionNumber.ToString)
End SyncLock
End Function
Public Sub Clear() Implements System.Collections.IList.Clear
SyncLock Me.SyncRoot
_colFunctionInfo.Clear()
End SyncLock
End Sub
Public Function Contains(ByVal value As Object) As Boolean Implements System.Collections.IList.Contains
If _colFunctionInfo.Contains(value.IFunctionNumber.ToString) Then
Return True
Else
Return False
End If
End Function
Public ReadOnly Property Count() As Integer Implements System.Collections.ICollection.Count
Get
Return _colFunctionInfo.Count
End Get
End Property
Public ReadOnly Property IsReadOnly() As Boolean Implements System.Collections.IList.IsReadOnly
Get
Return False
End Get
End Property
Public Sub Remove(ByVal value As Object) Implements System.Collections.IList.Remove
If _colFunctionInfo.Contains(value.IFunctionNumber.ToString) Then
SyncLock Me.SyncRoot
_colFunctionInfo.Remove(value.IFunctionNumber.ToString)
End SyncLock
ReIndex()
End If
End Sub
Public Function GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
Return _colFunctionInfo.GetEnumerator
End Function
Public Sub Insert(ByVal index As Integer, ByVal value As Object) Implements System.Collections.IList.Insert
SyncLock Me.SyncRoot
If _colFunctionInfo.Contains(value.IFunctionNumber.ToString) Then
_colFunctionInfo.Remove(value.IFunctionNumber.ToString)
End If
If index < _colFunctionInfo.Count Then
_colFunctionInfo.Add(value, value.IFunctionNumber.ToString, index - 1)
Else
_colFunctionInfo.Add(value, value.IFunctionNumber.ToString)
End If
End SyncLock
ReIndex()
End Sub
Public Sub RemoveAt(ByVal index As Integer) Implements System.Collections.IList.RemoveAt
SyncLock Me.SyncRoot
If _colFunctionInfo.Count <= index And index > 0 Then
_colFunctionInfo.Remove(index)
End If
End SyncLock
ReIndex()
End Sub
Private Sub ReIndex()
SyncLock Me.SyncRoot
Dim iReIndex As Integer = 1
Dim colTemp As New Collection
For Each obj As clsFunctionInfo In _colFunctionInfo
obj.IdxFunction = iReIndex
colTemp.Add(obj, obj.IFunctionNumber)
iReIndex += 1
Next
_colFunctionInfo.Clear()
For Each obj1 As clsFunctionInfo In colTemp
_colFunctionInfo.Add(obj1, obj1.IFunctionNumber.ToString)
Next
colTemp.Clear()
End SyncLock
End Sub
Public ReadOnly Property IsSynchronized() As Boolean Implements System.Collections.ICollection.IsSynchronized
Get
Return True
End Get
End Property
Public ReadOnly Property SyncRoot() As Object Implements System.Collections.ICollection.SyncRoot
Get
Dim _syncRoot As New Object
Return _syncRoot
End Get
End Property
Public ReadOnly Property IsFixedSize() As Boolean Implements System.Collections.IList.IsFixedSize
Get
Return False
End Get
End Property
Public Sub CopyTo(ByVal array As System.Array, ByVal index As Integer) Implements System.Collections.ICollection.CopyTo
For Each obj As clsFunctionInfo In _colFunctionInfo
array(index) = obj
index += 1
Next
End Sub
Public Function IndexOf(ByVal value As Object) As Integer Implements System.Collections.IList.IndexOf
SyncLock Me.SyncRoot
Dim tmpFnInfo As New clsFunctionInfo
Dim tmpFunctionNumber As Integer
Dim tmpidx As Integer = -1
tmpFnInfo = DirectCast(value, clsFunctionInfo)
tmpFunctionNumber = tmpFnInfo.IFunctionNumber
For Each obj In _colFunctionInfo
tmpFnInfo = DirectCast(obj, clsFunctionInfo)
If tmpFunctionNumber = tmpFnInfo.IFunctionNumber Then
tmpidx = tmpFnInfo.IdxFunction
Exit For
End If
Next
Return tmpidx
End SyncLock
End Function
Default Public Property Item(ByVal index As Integer) As Object Implements System.Collections.IList.Item
Get
index += 1
Return _colFunctionInfo(index)
End Get
Set(ByVal value As Object)
End Set
End Property
End Class
I'm sorry that this is so long, but I know that someone on here has some great suggestions on how to handle this because I'm having a little trouble wrapping my head around it. I think I've been starring at it too long.
since you have the text file as an embedded resource, you can open a stream to the file from there, without having to write it to disk. The ResourceReader class should help you.