Single-character strings not writing to file correctly - vb.net

Having trouble with my code, I resort to writing the contents of my arrays to file, like this:-
Private Sub DumpArray (ByRef array_to_dump(,) As MyEnum, ByVal file_name As String)
Dim sw As StreamWriter = New StreamWriter(file_name)
For i As Integer = array_to_dump.GetLowerBound(0) To array_to_dump.GetUpperBound(0)
For j As Integer = array_to_dump.GetLowerBound(1) To array_to_dump.GetUpperBound(1)
If array_to_dump(i, j) = MyEnum.This Then
sw.Write("Fred")
Else
sw.Write("Bert")
End If
sw.Write(vbTab)
Next j
sw.WriteLine
Next i
sw.Flush
sw.Close
End Sub
This produces the output I expect; in the current case a file filled with "Fred", separated by tabs. However, if I change the business end of the code to this:-
If array_to_dump(i, j) = MyEnum.This Then
sw.Write("1")
Else
sw.Write("0")
End If
the file is filled with non-printing characters, that come out as little boxes in Notepad, rather than the rows of "0" separated by tabs that I was expecting. Any other pairs of single-character strings do the same.
While not a matter of pressing importance, I am idly curious as to why this should be. Does anyone know?

You will have to set the encoding to something else when you declare your SteamWriter like #DavidSdot said. Like so:
Dim writer As StreamWriter = New StreamWriter(file_name, Encoding.Default)
Mess around with that property and you will probably find a good value. I'm no expert in encoding but this should be the culprit of your problem.

I tried to repro the problem but the code below works correctly. Compare it to your real code... maybe there is a typo or something in the original?
Option Strict On
Imports System.IO
Public Class Form1
Private Enum MyEnum As Integer
This
That
End Enum
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim myArray(1, 1) As MyEnum
myArray(0, 0) = MyEnum.This
myArray(0, 1) = MyEnum.This
myArray(1, 0) = MyEnum.This
myArray(1, 1) = MyEnum.That
Call DumpArray(myArray, "C:\Junk\Junk.txt")
End Sub
Private Sub DumpArray(ByRef array_to_dump(,) As MyEnum, ByVal file_name As String)
Dim sw As StreamWriter = New StreamWriter(file_name)
For i As Integer = array_to_dump.GetLowerBound(0) To array_to_dump.GetUpperBound(0)
For j As Integer = array_to_dump.GetLowerBound(1) To array_to_dump.GetUpperBound(1)
If array_to_dump(i, j) = MyEnum.This Then
sw.Write("0")
Else
sw.Write("1")
End If
sw.Write(vbTab)
Next j
sw.WriteLine()
Next i
sw.Flush()
sw.Close()
End Sub
End Class

Related

Utilizing wildcards and variables for getFiles

I am kinda new to VB.net, so I am not sure if I try this the right way. I have the following piece of code.
Dim objReader As New System.IO.StreamReader(FILE_NAME)
Dim TextLine As String
Do While objReader.Peek() <> -1
Dim newString As String = TextLine.Replace(vbCr, "").Replace(vbLf, "") & ".wav"
Dim SongName As String = My.Computer.FileSystem.GetName(newString)
Dim MyFile As String = Dir("C:\AllSongs\" & newString)
Dim Searchquery As IEnumerable(Of String) = IO.Directory.EnumerateFiles("C:\AllSongs", "*", IO.SearchOption.AllDirectories).Where(Function(f) IO.Path.GetFileNameWithoutExtension(f).IndexOf(SongName, StringComparison.CurrentCultureIgnoreCase) >= 0)
For Each Result In Searchquery
ListBox1.Items.Add(Result)
Next
I am trying to use the lines in the text file, and get the .wav in AllSongs dir that partially correspond in these files. Can it be done?
Edit: Part of the code contains a media player. I want to be able to play songs from this player, by choosing files in the list.
Private Sub ListBox1_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles ListBox1.DoubleClick
AxWindowsMediaPlayer1.URL = ListBox1.SelectedItem
Dim variables As New Dictionary(Of String, String)()
Dim selectedItem As Object = ListBox1.SelectedItem
variables("MyDynamicVariable") = selectedItem ' Set the value of the "variable"
selectedItem1 = selectedItem
Dim value As String = variables("MyDynamicVariable") ' Retrieve the value of the variable
End Sub
Incidental to the question, but important, is that when you're working with files it's often necessary to clean up some resources (file handles, I guess) that the operating system uses even though you don't see it directly in the code as written. There is a way of doing that automatically with the Using statement, as shown in the following code.
To find out if a filename contains some text (string), you can extract the filename with no path or extension with Path.GetFileNameWithoutExtension and check if it contains the desired string with the IndexOf function, which lets you ignore uppercase/lowercase by specifying how to do the check.
I notice from an update to the question that some improvements can be made, such as using a Class for the song entries so that the displayed list can have more information behind it, which means that the song name can be shown on its own but you can get the full path to the file when you click on it.
I made a new Windows Forms project and added just a ListBox to it, and used this code to show the full path (which you can use for your media player) to the song when its name is double-clicked:
Imports System.IO
Public Class Form1
Public Class SongEntry
Property Name As String
Property FullName As String
End Class
Sub PopulateSongList(musicDirectory As String, songsList As String)
Dim songList As New List(Of SongEntry)
Using sr As New System.IO.StreamReader(songsList)
Do While Not sr.EndOfStream
Dim thisSong = sr.ReadLine()
If thisSong <> "NaN" Then
Dim fs = Directory.EnumerateFiles(musicDirectory, "*.wav", SearchOption.AllDirectories).
Where(Function(f) Path.GetFileNameWithoutExtension(f).IndexOf(thisSong, StringComparison.CurrentCultureIgnoreCase) >= 0).
Select(Function(g) New SongEntry With {.Name = Path.GetFileNameWithoutExtension(g), .FullName = g})
songList.AddRange(fs)
End If
Loop
End Using
ListBox1.DataSource = songList
ListBox1.DisplayMember = "Name"
ListBox1.ValueMember = "FullName"
End Sub
Private Sub ListBox1_DoubleClick(sender As Object, e As EventArgs) Handles ListBox1.DoubleClick
Dim lb = DirectCast(sender, ListBox)
If lb.SelectedIndex >= 0 Then
Dim fullPathToSong = lb.SelectedValue.ToString()
MsgBox(fullPathToSong)
End If
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim songsList = "C:\temp\AllSongs\songsList.txt"
Dim musicDirectory = "C:\temp\AllSongs"
PopulateSongList(musicDirectory, songsList)
End Sub
End Class

What does it mean by variable has been used before it has been assigned a value?

I created this program with the intention of bubble sorting "numbers.txt" textfile. But the line below that is bolded is giving me an error of variable has been used before it has been assigned a value. Can someone help me at this? I seem to cant figure out this line numbers2(z) = numbers(z). Cause every time I load this program, it crashes on me. I would love someone to give me some assistance
Public Class Form1
Dim currentLine As String = ""
Dim data As New System.IO.StreamReader("numbers.txt")
Dim counter As Integer = 0
Dim currentValue As Integer
Dim previousValue As Integer
Dim nextValue As Integer
Dim isLoaded As Boolean = False
Dim numbers As String()
Dim numbers2 As String()
Public Sub btnSort_Click(sender As Object, e As EventArgs) Handles btnSort.Click
If (Not isLoaded) Then
MessageBox.Show("You have not loaded")
Else
For j = 0 To counter
If (j = 0) Then
currentValue = CInt(numbers2(j))
nextValue = CInt(numbers2(j + 1))
If (currentValue > nextValue) Then
numbers2(j + 1) = numbers2(j)
numbers2(j) = numbers(j + 1)
End If
ElseIf (j = counter) Then
Continue For
ElseIf (j = counter - 1) Then
currentValue = CInt(numbers2(j))
previousValue = CInt(numbers2(j - 1))
If (currentValue > previousValue) Then
'Good
ElseIf (currentValue < previousValue) Then
numbers2(j - 1) = numbers2(j)
numbers2(j) = numbers(j - 1)
End If
Else
currentValue = CInt(numbers2(j))
previousValue = CInt(numbers2(j - 1))
nextValue = CInt(numbers(j + 1))
If (currentValue < nextValue) Then
'Good
ElseIf (currentValue > nextValue) Then
numbers2(j + 1) = numbers2(j)
numbers2(j) = numbers(j + 1)
End If
If (currentValue > previousValue) Then
'Good
ElseIf (currentValue < previousValue) Then
numbers2(j - 1) = numbers2(j)
numbers2(j) = numbers(j - 1)
End If
End If
Next
For k = 0 To counter
tbOutput.Text += numbers2(k) & vbCrLf
Next
For z = 0 To counter
numbers(z) = numbers2(z)
Next
End If
End Sub
Public Sub btnLoad_Click(sender As Object, e As EventArgs) Handles btnLoad.Click
Dim numbers As String() = currentLine.Split(New String() {Environment.NewLine}, StringSplitOptions.None)
Dim numbers2 As String()
Do While data.Peek() <> -1
'Appends currentline with results from data.readline and a new line
currentLine = currentLine & data.ReadLine() & vbNewLine
'shows the amount of lines in the file
counter += 1
Loop
'displays content from the file
tbInput.Text = currentLine
'sets
For z = 0 To counter
**numbers2(z) = numbers(z)**
Next
isLoaded = True
End Sub
Private Sub tbOutput_TextChanged(sender As Object, e As EventArgs) Handles tbOutput.TextChanged
End Sub
End Class
Fundamentally, this question speaks to understanding of the differences between variables, object references, object instances, and types. Until you really understand those differences, you will continue to struggle as a coder. Don't feel bad; you're far from alone here, and once you do get this suddenly everything is a whole lot easier.
numbers2 is a variable. Like all variables in .Net, numbers2 has a specific type: in this case, string array, which is a reference type. But that is not the same thing as saying numbers2 is itself an array. An actual array is an instance of an Object, and like all object instances exists off in memory somewhere separate from any variable. You must then give the numbers2 variable a reference to the array object. References connect variables with objects.
The reference is not the object, because there may be many references all pointing to the same object. But without a reference, an object is useless and the memory will be reclaimed by the garbage collector. The reference is not the variable, because one variable may have several different references assigned to it over its lifetime. But for the span of time the reference is assigned, the value of the variable is that reference. And a variable most certainly is not (by itself) an object. Even the Form1 variable is simply an object reference variable, and you could assign a whole new Form1 object instance to it (that VB.Net allows you to have variables and types with the same name can be frustrating, and I believe doing this by default with Windows forms is the source of much confusion in this whole "types vs reference vs object" area for many new programmers).
One way to assign a reference is while creating a new object. This is what happens when you see a Dim statement with the New keyword on the same line. This is also what happens when you have a Dim statement for array that includes a subscript (size), such as Dim items(4) As String or Dim items As String(4). The compiler here will automatically create the array object. But if you don't include a size for an array (Dim numbers2() As String), the compiler does not yet have enough information to create the array, because it doesn't know how big the object needs to be. So now you have an object reference variable, but there's no object instance assigned to it yet.
Now we know enough to begin debugging this program.
We'll start in the Load method. The beginning of this method re-declares the numbers and numbers2 arrays:
Dim numbers As String() = currentLine.Split(New String() {Environment.NewLine}, StringSplitOptions.None)
Dim numbers2 As String()
This means the method is working with completely different variables from the arrays defined at the top of the class, and so later on, in the Sort method, there's no data; the arrays are still null/Nothing.
Additionally, the declaration for numbers2 doesn't assign anything. It just creates an empty array reference. This is different than having an array object with 0 elements. There is no array object here at all yet. This is what causes the exception on the line indicated. You are trying to use a numbers2 reference variable before any object has been assigned to it.
To fix things, what I would do first of all is separate the event handlers from the code that does work; limit event code as much as possible to the statements the deal with reading and writing control properties. We'll make a new LoadData() function which accepts an argument and returns a value. The new method is not concerned with any textboxes, global or classs variables, or controls. It merely knows how to read the data in the format most appropriate for the data:
Public Function LoadData(fileName As String) As IEnumerable(Of Integer)
Return File.ReadLines(fileName).Select(Function(line) Integer.Parse(line.Trim()))
End Function
Now the existing Load method can call this function. Even better if this method handles the Form_Load, Form_Shown, Form_Activated, or similar event depending on what is most appropriate for your application, rather than a button click. Also, let's choose a better type for our numbers object:
Private numbers As List(Of Integer)
Public Sub Form1_Load(sender As Object, e As EventArgs) Handles Form1.Load
numbers = LoadData("numbers.txt").ToList()
tbInput = String.Join("\n", numbers)
End Sub
We could make this more efficient by removing a conversion back to string, but that version requires a lot more code, and it's won't make a meaningful difference until you have very large collections.
Now let's look at the sort method:
Public Sub btnSort_Click(sender As Object, e As EventArgs) Handles btnSort.Click
If numbers Is Nothing OrElse numbers.Count = 0 Then
MessageBox.Show("You have not loaded")
Return
End If
numbers = numbers.OrderBy(Function(n) n).ToList()
tbOutput.Text = String.Join("\n", numbers)
End Sub
Put it all together:
Public Class Form1
Private numbers As List(Of Integer)
Public Sub btnSort_Click(sender As Object, e As EventArgs) Handles btnSort.Click
If numbers Is Nothing OrElse numbers.Count = 0 Then
MessageBox.Show("You have not loaded")
Return
End If
numbers = numbers.OrderBy(Function(n) n).ToList()
tbOutput.Text = String.Join("\n", numbers)
End Sub
Public Sub Form1_Load(sender As Object, e As EventArgs) Handles Form1.Load
numbers = LoadData("numbers.txt").ToList()
tbInput = String.Join("\n", numbers)
End Sub
Public Function LoadData(fileName As String) As IEnumerable(Of Integer)
Return File.ReadLines(fileName).Select(Function(line) Integer.Parse(line.Trim()))
End Function
End Class
Now I suspect this is course work, where your instructor does not want you to use OrderBy() or Array.Sort(). But even in that case, follow the example from the LoadData() function: create a method separate from the button event handler which accepts an IEnumerable(Of Integer) and returns a sorted IOrderedEnumerable(Of Integer), and use the button click event handler to call this method. The result will be code that retains this same basic structure, where you still only need the one class-level variable.

Parsing String into an Array (VB)

I have tried to make a program that would parse a raw list from Chrome://policy (input by RichTextbox) into a text array, then dump it into another RichTextbox. All of the raw string are exactly 32 characters long, followed by a comma. Here is the code:
Public Class Form1
Dim tempExt As String
Dim extsHandled As Integer
Dim numOfExts As Integer
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If RichTextBox1.Text = "" Then
MsgBox("Please enter the raw extensions from Chrome://policy")
Else
RichTextBox3.Text = RichTextBox1.Text
numOfExts = TextBox1.Text
Dim place As Integer = 0
Dim exts(150) As String
While extsHandled < numOfExts
tempExt = RichTextBox1.Text.Substring(0, 32)
exts(place) = tempExt
RichTextBox1.Text.Remove(0, 33)
place = place + 1
extsHandled = extsHandled + 1
End While
Dim newPlace As Integer = 0
While newPlace < numOfExts
RichTextBox2.AppendText(exts(newPlace))
newPlace = newPlace + 1
RichTextBox2.AppendText(" ")
End While
End If
End Sub
End Class
Most of it works, but it would seem something is going wrong with removing the characters from the richtextbox, as when I run it, it only parses the first part of the string over and over:
Am I doing something wrong?
If it's always like that you can do it like this:
RichTextBox3.Text = RichTextBox1.Text.Replace(",", vbNewLine)
The #3 is your result, while #1 is original right?
Ah yeah, you can count how many there simply by
RichTextBox2.Text= RichTextBox1.Text.Split({","}, StringSplitOptions.RemoveEmptyEntries).Count.ToString
This line returns a new string:
RichTextBox1.Text.Remove(0, 33)
It does not modify the textbox in place. The next iteration through the loop, you're still working with the original value, looking at the same set of 32 characters at the beginning of the string.
Additionally, nothing in this code initializes the extsHandled variable. You should turn on Option Strict, which helps catch that kind of error. Running of Option Strict off is poor practice. You should also give a meaningful name to any control you will actually reference from code.
It's not clear to me right now the exact format. If it's all on the same line (no line break characters as part of the string, even if it wraps), this should work:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If String.IsNullOrWhitespace(RichTextBox1.Text) Then
MsgBox("Please enter the raw extensions from Chrome://policy")
Exit Sub
End If
RichTextBox3.Text = RichTextBox1.Text
Dim exts() As String
Using rdr As New TextFieldParser(RichTextBox1.Text)
rdr.TextFieldType = FileIO.FieldType.Delimited
rdr.Delimiters = New String() {","}
exts = rdr.ReadFields()
End Using
For Each ext As String In exts
RichTextBox2.AppendText(ext)
Next ext
RichTextBox1.Text = ""
End Sub
The problem is this code doesn't do anything. The array is gone when the method ends. Consider making the array a property of the class, or having method that returns the array as the result.
You can also look at this, to save typing into the textbox, though it's just a starting point:
Public Function GetChromeExtensionKeys() As IEnumerable(Of String)
Dim BasePath As String =
EndEnvironment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
BasePath = Path.Combine(BasePath, "Google\Chrome\User Data")
Dim dflt As String = Path.Combine(BasePath, "Default\Extensions")
Dim profileExts() As String = Directory.GetDirectories(BasePath, "Profile *").
Select(Function(p) Path.Combine(p, "Extensions"))
Dim result As New List(Of String)()
result.AddRange(Directory.GetDirectories(dflt))
For Each folder As String In profiles
result.AddRange(Directory.GetDirectories(folder))
Next folder
Return result.Select(Function(e) Path.GetFileName(e)).Distinct()
Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For Each ext As String In GetChromeExtensionKeys()
RichTextBox2.AppendText(ext)
Next ext
End Sub

How do I optimize my code - vb.net

I have a working program, but it's like Frankenstein - parts of other programs put together, that may be redundant. Here's what I'm trying to do:
Find a string inside a binary file & from that location to the EOF dump the contents into a string.
Here is my code:
Imports System.IO
Public Class Form1
Dim b() As Byte = IO.File.ReadAllBytes("C:\data.bin")
Dim encodme As New System.Text.ASCIIEncoding
Dim SearchString As String = "xyzzy"
Dim bSearch As Byte() = encodme.GetBytes(SearchString)
Dim bFound As Boolean = True
Dim oneByte As Byte
Dim fileData As New IO.FileStream("C:\data.bin", FileMode.Open, FileAccess.Read)
Dim strMessage As String
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
For i As Integer = 0 To b.Length - bSearch.Length - 1
If b(i) = bSearch(0) Then
bFound = True
For j As Integer = 0 To bSearch.Length - 1
If b(i + j) <> bSearch(j) Then
bFound = False
Exit For
End If
Next
If bFound Then
fileData.Seek(i + 5, SeekOrigin.Begin)
strMessage = ""
For r As Integer = (i + 5) To fileData.Length() - 1
oneByte = fileData.ReadByte()
strMessage = strMessage + Chr(oneByte)
Next r
MsgBox(strMessage)
Else
MsgBox("File Doesn't have string")
Exit Sub
End If
End If
Next
End Sub
End Class
When looking for performance, it is best to avoid trying to walk through this kind of thing byte by byte. Instead you should use the facilities .NET provides you with. This example uses RegEx to find all matches of a string in any file, returning each match with everything that follows it until the next match or the end of the file in a UTF-8 string:
Imports System.IO
Imports System.Text
Imports System.Text.RegularExpressions
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim matches = FindStringMatchesInFile("C:\Infinite Air\snowboarding.exe", "data")
For Each m In matches
...
Next
End Sub
Private Function FindStringMatchesInFile(filename As String,
searchString As String) As List(Of String)
Dim output As New List(Of String)
Dim reader = New StreamReader(filename, Encoding.UTF8)
Dim re = New Regex(String.Format("{0}(?:(?!{0}).)*", searchString),
RegexOptions.Singleline Or RegexOptions.IgnoreCase,
Regex.InfiniteMatchTimeout)
Dim matches = re.Matches(reader.ReadToEnd())
For Each m As Match In matches
output.Add(m.ToString())
Next
Return output
End Function
End Class
The RegEx pattern definition is the following:
Matches the characters {searchString} literally (case insensitive)
Non-capturing group (?:(?!{searchString}).)*
* Quantifier — Matches between zero and unlimited times, as many times as possible, giving back as needed (greedy)
Negative Lookahead (?!{searchString})
Assert that the Regex below does not match
Matches the characters {searchString} literally (case insensitive)
. matches any character
Global pattern flags
g modifier: global. All matches (don't return after first match)
s modifier: single line. Dot matches newline characters
i modifier: case insensitive.

Resizing an array at runtime in VB.NET

In my Windows Forms application at runtime I will be resizing an array each time I add an element. So first I must resize to the size + 1, and then add a member to this index. How do I do this?
You could use the ReDim statement, but this really isn't your best option. If your array will be changing sizes often, especially as it sounds like you're just appending, you should probably use a generic List(Of T) or similar collection type.
You can use it just like you use an array, with the addition that adding an item to the end is as easy as MyList.Add(item)
To use a generic list, add Imports System.Collections.Generics to the top of the file. Then, you would declare a new integer list like this:
Dim MyList As New List(Of Integer)()
or a string list like this:
Dim MyList As New List(Of String)()
You should get the idea.
The suggested ReDim's need the Preserve keyword for this scenario.
ReDim Preserve MyArray(n)
Using a generic list is (as suggested) the best idea. If you however want to change the size of an Array, you can use Array.Resize(ByRef arr, newSize).
ReDim is not a good (pretty bad) idea (VB specific legacy, extremely slow).
I would prefer some type of collection class, but if you WANT to use an array do it like this:
Dim arr() As Integer
Dim cnt As Integer = 0
Dim ix As Integer
For ix = 1 To 1000
cnt = cnt + 1
ReDim arr(cnt)
arr(cnt - 1) = ix
Next
You can also make your own collection class. A good programming exercise for new programmers.
Public Class MyList
Private Items() As String
Private No As Integer = 0
Public Sub Add(ByVal NewItem As String)
''Create a temporary new string array
Dim CopyString(No) As String
''Copy values from Global Variable Items() to new CopyString array
For i As Integer = 0 To No - 1
CopyString(i) = Items(i)
Next
''Add new value - NewItem - to CopyString
CopyString(No) = NewItem
''Increment No to No + 1
No += 1
''Copy CopyString to Items
Items = CopyString
'Discard CopyString
CopyString = Nothing
End Sub
Public Sub Show(ByVal index As Integer)
MsgBox(Items(index))
End Sub
End Class
''Now create a form with a TextBox name - txt, Button1 and Button2
Public Class Form1
''Declare txts as a new MyList Class
Private txts As New MyList
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
''Add text to txts which is a MyList Class
txts.Add(txt.Text)
txt.Text = ""
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
''Display value at a specific index
txts.Show(Convert.ToInt16(txt.Text))
txt.Text = ""
End Sub
End Class
Use the ReDim command to specify the new size.
ReDim MyArray(MyArray.Length + 1)
As Joel says, use a list.
Dim MyList As New List(Of String)
Don't forget to change Of String to be Of whichever datatype you're using.
This work for me
Dim Table1 As New DataTable
' Define columns
Table1.Columns.Add("Column1", GetType(System.String))
Table1.Columns.Add("Column2", GetType(System.Int32))
Table1.Columns.Add("Column3", GetType(System.Int32))
' Add a row of data
Table1.Rows.Add("Item1", 44, 99)
Table1.Rows.Add("Item2", 42, 3)
Table1.Rows.Add("Item3", 42, 3)
Table1.Rows.Add("Item4", 42, 3)
Dim arr(-1) As String
For Each dr As DataRow In Table1.Rows
ReDim Preserve arr(arr.Length)
arr(arr.Length - 1) = dr("Column1")
Next