MadsTheMan MadsTheMan - 4 months ago 43
Vb.net Question

VB.net load controls and content from textfile to textboxes

...Hopefully this question will be readable...

I have 27 textboxes.

enter image description here

The controlname and the text in the textboxes are written to a textfile like this:

System.DateTime.Now.ToString("yyyyMMdd") & "_Names_Config.txt"
Dim objWriter As New System.IO.StreamWriter(configfile, True)
'Textboxes
objwriter.Writeline("tbmax1") 'Control name
objwriter.Writeline("tbmax1.text) 'The text in the textbox
objWriter.WriteLine("tbname1") 'Control name
objWriter.WriteLine(tbname1.Text) 'The text in the textbox
objWriter.WriteLine("tbext1") 'Control name
objWriter.WriteLine(tbext1.Text) 'The text in the textbox
'And so on for all the the controls


This goes on for all the textboxes and controls, so 54 lines in total.

Works great. The textfile looks like this:

enter image description here

Alright, now the issue. There will be a
load button
that should search the textfile -> find the control matching the form's control -> use the line below and fill that spesific line in the control's textbox -> then find next control and do the same.

Load button: This is #1 attempt;



'Openfiledialog, then:
Using reader As New StreamReader(OpenFileDialog1.FileName.ToString)
Dim currentTextBox As TextBox = Nothing
While reader.Peek > -1
Dim line As String = reader.ReadLine()
If Not String.IsNullOrEmpty(line) Then
Dim tmpTextbox = Controls.Find(line, True) 'Try to find text according to line
If tmpTextbox.Any() Then 'It´s a textbox name
currentTextBox = DirectCast(tmpTextbox(0), TextBox)
Else
'?
End If
End If
End While
End Using


Here comes what I don't understand at all. See before and after picture of what happens to the 27 textboxes after I load the textfile.

What it SHOULD look like:

enter image description here

What it will look like:

enter image description here

"Edit channels" is actually the title of the form itself. I'm speechless. Because I totally don't understand why this happens and the load code, I moved on to another attempt.

#2 attempt:



Using reader As New StreamReader(OpenFileDialog1.FileName)
Dim Line As String = reader.ReadLine()
Dim Current As Integer = 0
Dim TB As TextBox = Nothing
While Not IsNothing(Line) 'It will be Nothing when file is over

'__________________________________________________________________1
If Line.StartsWith("tbext1") Then
'We will increment CurrentChannel, as we changed the section
Current += 1
For onetonine = 1 To 9
tbext1.Text = Line
Next
End If
If Line.StartsWith("tbname1") Then
'We will increment CurrentChannel, as we changed the section
Current += 1
For onetonine = 1 To 9
tbname1.Text = Line
Next
End If
If Line.StartsWith("tbmax1") Then
'We will increment CurrentChannel, as we changed the section
Current += 1
For onetonine = 1 To 9
tbmax1.Text = Line
Next
End If
'__________________________________________________________________2
'Then I guess this would go on for all the 27 textboxes (probably a really bad attempt)

End While
End Using


However, this just goes into break mode.

Answer

Your first approach works already if you fill the Else part:

If tmpTextbox.Any() Then
    currentTextBox = DirectCast(tmpTextbox(0), TextBox)
ElseIf currentTextBox IsNot Nothing Then
    currentTextBox.Text = line
End If

But you should not use it in production code:

  • Control-names are a very bad key for a database record or file entry:
    • They can change in future and you won't notice it
    • They are GUI related and not supposed to be identifiers for properties
    • is not fail-safe because there could be multiple controls with the same name
  • don't store key-value pairs on different lines, that makes it difficult, less readable and more error-prone to put them together afterwards

If you want to use one line you need a delimiter that a user never enters, it can be a combination of multiple characters like |::| or something similar. Then you can later use String.Split({"|::|"}, StringSplitOptions.None) to get both tokens back.

However, this is still not a good approach and also not 100% safe. So better approaches were

  • serialize/deserialize a List(Of String).
  • If you want to store it in a way that a human can read you should prefer XML.

Here's an example how you can write/read xml easily:

' write all TextBoxes to a file '
Dim allTextBoxes = TextBoxPanel.Controls.OfType(Of TextBox)()

Dim doc As New XDocument(New XElement("Channels"))
For Each txt In allTextBoxes
    doc.Root.Add(New XElement(txt.Name, txt.Text.Trim()))
Next
doc.Save(OpenFileDialog1.FileName)

' later read it ... '
Dim xml As XDocument = XDocument.Load(OpenFileDialog1.FileName)
For Each element As XElement In xml.Descendants("Channels").Descendants()
    Dim txt = allTextBoxes.FirstOrDefault(function(t) t.Name = element.Name)
    If txt IsNot nothing
        txt.Text = element.Value 
    End If
Next