1

This is more of a design/user experience kind of question, so if it belongs somewhere else please let me know.

I have a program that has multiple PictureBoxes:

PictureBox1
PictureBox2
.
.
PictureBox60

Each PictureBox's Tag field is filled in with a String value. When the user clicks on a picture box, the Tag property is put inside a ListBox, and I manually order them:

1. ListBox item 1
2. ListBox item 2
3. ListBox item 3
etc

Each line is also written to a text file, again with the line number preceeding the item.

Condition 1: If there are already items in the file, it detects how many lines are currently in the file and continues the numbering, so the file begins with 1. Example:

File1.txt already contains

1. Bob
2. Sally
3. Joe

and the ListBox is empty. If a PictureBox with the Tag "Charles" is clicked, the ListBox now contains:

1. Charles

and File1.txt now contains

1. Bob
2. Sally
3. Joe
4. Charles

Condition 2: The file does not yet exist, and therefore when items are added to the ListBox and written to the file, the file is created and they are listed in the file the same way as above. The file items are numbered beginning with 1.

Condition 3: The file exists, but is empty. I want, regardless of the existence of the file, the numbering in said file to begin with 1 and continue the numbering.

Here is the code I have to handle these three conditions. It just feels so messy and unprofessional, but maybe I just need the approval of others to make it feel less so.

Private Sub saveToFile(boss As String, item As String)

    ' lineCount used so we know where to append in the file i.e. if there were already 5 lines we know to append at the 6th line
    ' + 1 to use 1 indexing
    Dim lineCount As Integer
    Dim fileExists As Boolean = False
    ' vars to retrieve item from ItemDropListBox and extract only the item name
    Dim lastItem As String = ItemDropListBox.Items.Item(ItemDropListBox.Items.Count - 1)
    Dim periodIndex As Integer = lastItem.IndexOf(".") + 2
    Dim itemStringLength As Integer = lastItem.Length - periodIndex
    Dim trimmedItem As String = lastItem.Substring(periodIndex, itemStringLength)

    Dim sw As IO.StreamWriter

    ' TODO just me being nitpicky
    '   [x] - If file doesn't exist, create it and being first item at 1
    '   [x] - If file does exist AND there is already items in it, write to it with correct order
    '   [x] - If file does exist and there is NOT items in it, write to it with correct order

    ' If the file exists, want to
    If My.Computer.FileSystem.FileExists(My.Application.Info.DirectoryPath & "/logs/" & boss & ".txt") Then
        lineCount = IO.File.ReadAllLines(My.Application.Info.DirectoryPath & "/logs/" & boss & ".txt").Count
        fileExists = True
    Else
        lineCount = 1
        fileExists = False
    End If

    ' True indicates append to file instead of overwrite
    sw = New IO.StreamWriter(My.Application.Info.DirectoryPath & "/logs/" & boss & ".txt", True)

    If fileExists = True Then
        ' Write the new item to the file
        sw.WriteLine((lineCount + 1) & ". " & trimmedItem)
    Else
        sw.WriteLine(lineCount & ". " & trimmedItem)
    End If


    ' Close file
    sw.Close()
End Sub

Question: Am I trying too hard to fix a problem that will never happen? The files will 99.9% of the time never be created by the user, only by the code, so the chance of them even having a file exist with nothing inside is already very slim. I could have much more elegant code if I didn't worry about handling this small chance.

I have also already considered moving to C#. The original idea was to create it in VB then re-create in C#, but I think that would be a waste of time and I have enough experience that I think C# would do just fine. Plus from what I can tell I would have much more control over things I want to change.

Edit: Moving all the code over to C# - there's not that much and I feel too limited with VB (not even regarding this question)

0

2 Answers 2

3

The key is to subdivide your problem into smaller tasks first:

  • separate input, processing and output into three functions

  • the input function should read the file and return a list of strings. If the file does not exist, it should return an empty list of strings (and not more!). Note there is no need to remember the information if the file existed in the first place for the further processing. There is also no reason to distinguish the cases of an empty file or a non-existing file.

  • the processing function should get a list of strings as input, the string to be added, and it should return the new list of strings. Note that dealing with the empty list as input should not be really different from dealing with non-empty lists

  • the output function should take the list of strings and write it back into the file. Note you do not have to tell the StringWriter explicitly that it should create a new file if it does not exist, it will do it automatically for you if you use it in "overwrite" mode instead of append mode (so in your code, it should be instantiated like New IO.StreamWriter(filename, False).

As you see, dealing with empty files or non-existing vs. existing files is only a minor issue here, so making your program robust enough to handle these cases is nothing which should cause you a headache.

A final note for porting the VB code to C#: maybe you know C# better than VB (like me), but VB.NET and C# have almost the same capabilities. For learning how to subdivide a bigger problem into smaller tasks, it is irrelevant which of the two languages you use.

1
  • Thanks for the comment, that helps quite a lot. I also think I was too focused on the overall product that I forgot to make the code more modular, which I value highly so thanks for the reminder!
    – follmer
    Aug 13, 2016 at 3:45
0

Have you considered whether you need numbers at all?

Condition 1: If there are already items in the file, it detects how many lines are currently in the file and continues the numbering

So, if there are three lines in the file and you add (append) another one, there will be four lines in the file:

Before   After 
-------  -------
Bob      Bob
Sally    Sally
Joe      Joe
         Charles

Condition 2: The file does not yet exist ... The file items are numbered beginning with 1.

Before   After 
-------  -------
         Bob

Condition 3: The file exists, but is empty. ... the numbering in said file to begin with 1 and continue the numbering.

Before   After 
-------  -------
         Bob

As you can see, manual numbering is redundant, because the physical position of each line within the file defines the sequence of each item. If required, these sequence numbers can be easily derived as the file is read into the program, line-by-line.

I have also already considered moving to C#.

Whilst it is true that in the early days of .Net, the C# environment "acquired" new functionality [at least] a version ahead of its Visual Basic counterpart, this is no longer the case. Indeed, there is very little benefit of one language other the other, save your your personal experience/ comfort/ competence with whichever one you prefer.

Both languages have all the same Framework Classes available to them; there's practically nothing that you can do in one that you can't do in the other.

1
  • The line numbering is not required, but as there is a high probability of users opening and examining these files, it is important to know which item occurred on which "event" (number). I also already ported over to C#, I enjoy the layout and smaller things much more. Only took a few hours and I'm now already ahead of where I was. Thanks for the comment!
    – follmer
    Aug 13, 2016 at 3:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.