Adding records (Row/ Column) to DataGridView; Collection already belongs to a DataGridView control VB.NET - vb.net

I'm looking for some help with an issue I am having.
I have multiple text files, in a folder. The folder can have an "unlimited" amount of text files in it, although typically 2-150 files
http://gyazo.com/5f314d1ca374abf9f813914609dd931d (images for this + below, can't embed due to lack of reputation)
Each file then contains an "unlimited" (although typically 0-20 lines) amount of data inside it. Line 1 being the "test number" and line 2 being the "test result" - as seen in the image above
My Data Grid View has 3 columns in it (Username, test number, test result) - as seen in the image above
When running my code below; first record being added to the Data Grid View works perfectly, but the second (or any record after the first) the error occurs:
http://gyazo.com/0d492b97d918853e62c55ee314f3f181 (image) or error message:
"System.InvalidOperationException: Collection already belongs to a
DataGridView control. This operation is no longer valid. at
System.Windows.Forms.DataGridViewCellCollection.Add(DataGridViewCelldataGridViewCell)
at SpellingBee.TeacherMultiResults.TeacherMultiResults_Load(Object
sender, EventArgs e)"
This error occurs on the DGVRow.Cells.Add(DGVCell) 'add cell to row
One thing I don't want to do is change any of my text file/ folder structures, even though I'm aware that it is currently inefficient storage.
How can I fix this error? I'm using VB.net (Visual Studios 2013)
If you need any more information, please just ask
Many thanks.
Imports System.Windows.Forms
Imports System.IO
Public Class TeacherMultiResults
Dim AmountOfFiles
Dim LineCount As Integer = 0
Dim FileName As IO.FileInfo
Dim DGVRow As New DataGridViewRow
Dim DGVCell As DataGridViewCell
Dim Username As String = ""
Dim TestNumber As Integer = 0
Dim TestResult As Integer = 0
Private Sub TeacherMultiResults_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim directory As New IO.DirectoryInfo(LoadForm.CurrentDirectory & "\UserResults\") 'selects directory
Dim FileNames As IO.FileInfo() = directory.GetFiles()
Dim Files As IO.FileInfo
For Each Files In FileNames 'list the names of all files in the specified directory
Username = Files.ToString
Username = (Username.Substring(0, Username.Length - 4)) 'removes the .txt from the name
Try
LineCount = File.ReadAllLines(LoadForm.CurrentDirectory & "\UserResults\" & Username & ".txt").Length 'amount of lines in file
If LineCount > 1 Then
Dim Information As New System.IO.StreamReader(LoadForm.CurrentDirectory & "\UserResults\" & Username & ".txt") 'opens file
LineCount = LineCount / 2 'halfs line count
For i = 0 To LineCount - 1
TestNumber = Information.ReadLine() 'reads line to variable
TestResult = Information.ReadLine() 'reads line to variable
i = i + 1 'adds one to i
DGVCell = New DataGridViewTextBoxCell 'create a new DGV text box cell
DGVCell.Value = Username 'add value to DGV text box cell
DGVRow.Cells.Add(DGVCell) 'add cell to row
DGVCell = New DataGridViewTextBoxCell 'create a new DGV text box cell
DGVCell.Value = TestNumber 'add value to DGV text box cell
DGVRow.Cells.Add(DGVCell) 'add cell to row
DGVCell = New DataGridViewTextBoxCell 'create a new DGV text box cell
DGVCell.Value = TestResult 'add value to DGV text box cell
DGVRow.Cells.Add(DGVCell) 'add cell to row
DGV_MultiResults.Rows.Add(DGVRow) 'add row to DGV
Next
Information.Close() 'Close read
End If
Catch ex As Exception 'if file won't read
MsgBox(ex.ToString) 'show error
Exit Try
End Try 'end of try
Next 'end of files
End Sub
I hope that somebody can help me with this issue, I understand it's fairly simple to fix most probably although I can't seem to find a solution to the error!
Many thanks, Toby.

When working with a DataGridView, it is generally easier to just build an object list and then bind it to the DGV using the built-in data binding features.
For your example, it would look like this:
' Read the files, build objects as you go and add them to a list
Dim lst = New List(Of TeacherMultiResults)
' Replace this part with your file reading code...
Dim t1 = New TeacherMultiResults With {.Username = "Bob", .TestNumber = 1, .TestResult = 75}
lst.Add(t1)
Dim t2 = New TeacherMultiResults With {.Username = "Rick", .TestNumber = 1, .TestResult = 85}
lst.Add(t2)
Dim t3 = New TeacherMultiResults With {.Username = "Zoe", .TestNumber = 1, .TestResult = 95}
lst.Add(t3)
' Bind the list to the DataGridView
Dim bindList = New BindingList(Of TeacherMultiResults)(lst)
Dim bindSrc = New BindingSource
bindSrc.DataSource = bindList
grid.DataSource = bindSrc
Your grid should display each item of your list.

Related

Remove specific row of TableLayoutPanel using dynamically created button of each row

So I am making a function that will populate the TableLayoutPanel from FileDialog Result then make a delete button for each row using a loop. Here's the code
Private PathtoFile1 As New List(Of String) 'this will contain all the selected file in the dialogwindow
Private rowLineDrawing As Integer = 0
Private selectedfilecountLineDrawing As Integer
Public Function AttachFileLineDrawing(TLP As TableLayoutPanel)
Dim dr = OpenFileDialog1.ShowDialog
If (dr = System.Windows.Forms.DialogResult.OK) Then
selectedfilecountLineDrawing = OpenFileDialog1.FileNames.Count
For Each FileName In OpenFileDialog1.FileNames
Try
Console.WriteLine(FileName.ToString)
PathtoFile1.Add(FileName.ToString)
Catch SecEx As Security.SecurityException
MessageBox.Show("Security error. Please contact your administrator for details.\n\n" &
"Error message: " & SecEx.Message & "\n\n" &
"Details (send to Support):\n\n" & SecEx.StackTrace)
Catch ex As Exception
'Could Not Load the image - probably permissions-related.
MessageBox.Show(("Cannot display the image: " & FileName.Substring(FileName.LastIndexOf("\"c)) &
". You may not have permission to read the file, or " + "it may be corrupt." _
& ControlChars.Lf & ControlChars.Lf & "Reported error: " & ex.Message))
End Try
Next
'MAKE SOMETHING HERE TO DISPLAY THE SELECTED ITEMS IN THE TABLELAYOUTPANEL OF THE SUBMIT PROGRESS
TLP.Controls.Clear()
TLP.RowCount = 0
rowLineDrawing = 0
For Each Path In PathtoFile1
Dim filepath As New Label
filepath.Text = Path
filepath.Width = Val(360)
'this button is for previewing the file
Dim btnPreview As New Button
AddHandler btnPreview.Click,
Sub(s As Object, e As EventArgs)
Dim btn = CType(s, Button)
MsgBox("This is Preview")
End Sub
'This button is for removing rows in the tablelayoutpanel
Dim btnRmv As New Button
Dim StringToIndex As String = Path 'THIS CATCHES EVERY PATH IN THE LOOP AND STORE IT TO THE VARIABLE WHICH THEN BE USED AS A COMPARABLE PARAMETER FOR THE INDEX SEARCH
Dim index = PathtoFile1.IndexOf(Path)
AddHandler btnRmv.Click,
Sub(s As Object, e As EventArgs)
Dim btn = CType(s, Button)
MsgBox(index)
PathtoFile1.RemoveAt(index) 'THIS LINE OF CODE REMOVE THE SPECIFIC ITEM IN THE LIST USING THE BTNRMV CLICK
'MAKE SOMETHING HERE TO REMOVE THE ROW IN THE TABLELAYOUTAPANEL
End Sub
TLP.SuspendLayout()
TLP.RowStyles.Add(New RowStyle(SizeType.Absolute, 20))
TLP.Controls.Add(filepath, 0, rowLineDrawing)
TLP.Controls.Add(btnPreview, 1, rowLineDrawing)
TLP.Controls.Add(btnRmv, 2, rowLineDrawing)
TLP.ResumeLayout()
rowLineDrawing -= -1
Next
End If
End Function
So I am trying to remove the row in the TableLayoutPanel together with the dynamic control. My approach is removing the selected item in the list and I achieved it properly but can't remove the row in the TableLayoutPanel. Any help is much appreciated!
EDIT
I have tried to use the provided module above but got this error
And got this error
Here is an extension method that will enable you to remove any row from a TableLayoutPanel by index:
Imports System.Runtime.CompilerServices
Public Module TableLayoutPanelExtensions
<Extension>
Public Sub RemoveRowAt(source As TableLayoutPanel, index As Integer)
If index >= source.RowCount Then
Throw New ArgumentOutOfRangeException(NameOf(index),
index,
"The row index must be less than the number of rows in the TableLayoutPanel control.")
End If
'Remove the controls in the specified row.
For columnIndex = 0 To source.ColumnCount - 1
Dim child = source.GetControlFromPosition(columnIndex, index)
If child IsNot Nothing Then
child.Dispose()
End If
Next
'Move controls below the specified row up.
For rowIndex = index + 1 To source.RowCount - 1
For columnIndex = 0 To source.ColumnCount - 1
Dim child = source.GetControlFromPosition(columnIndex, rowIndex)
If child IsNot Nothing Then
source.SetCellPosition(child, New TableLayoutPanelCellPosition(columnIndex, rowIndex - 1))
End If
Next
Next
'Remove the last row.
source.RowCount -= 1
End Sub
End Module
I tested that on 3 column by 4 row TableLayoutPanel containing a Label in each cell executing the following code twice:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TableLayoutPanel1.RemoveRowAt(1)
End Sub
The result was as expected, i.e. removing the second-from-top row each time. You may need to fiddle a bit more depending on what you want to happen row heights. I had the row heights set to equal percentages so the remaining rows grew proportionally to fill the space. If you want something different, you can add code accordingly. Note that you could create an almost identical method for removing columns.

Read data from dynamically created text-box

I'm trying to collect data after creating dynamic text-box with vb.net
Private Sub btn_OK_lines_number_Click(sender As Object, e As EventArgs)
Handles btn_OK_lines_number.Click
Dim i As Integer
Dim x As Integer
Dim Z As Integer
Z = 150
If IsNumeric(txt_lines_number.Text) Then
Int32.TryParse(txt_lines_number.Text, x)
For i = 1 To x
Dim newTB As New TextBox
Dim newLB As New Label
newLB.Name = "lbl_workstation_number_line" & i
newLB.Text = "Nbr Work Station in Line" & i
newLB.Size = New Size(190, 20)
newLB.ForeColor = Color.White
newLB.Font = New Font("consolas", 12, FontStyle.Regular, GraphicsUnit.Pixel)
newLB.Location = New Point(20, Z + i * 30)
newTB.Name = "Textbox" & i
newTB.Size = New Size(170, 20)
newTB.Location = New Point(200, Z + i * 30)
Me.Controls.Add(newTB)
Me.Controls.Add(newLB)
Next
i = i + 1
Else
MessageBox.Show("please enter a number")
txt_lines_number.Text = ""
End If
End Sub
Let's say you just have one row, and only create one TextBox. You set the name here:
newTB.Name = "Textbox" & i
where the resulting TextBox is named Textbox1. The problem is you can't just reference the identifier Textbox1 directly in your code, as you do with txt_lines_number. You can't even reference it as a member of the class (Me.Textbox1). This name didn't exist at compile time, and so it's not an identifier you can use, and it's not a member of the class at all. There was never a matching Dim statement for that name.
What you can do, though, is look again in the Controls collection where you added the TextBox to the form:
Me.Controls("Textbox1")
or
Me.Controls("Textbox1").Text
You may also need to cast the value to a TextBox:
Dim box As TextBox = DirectCast(Me.Controls("Textbox1"), TextBox)
MessageBox.Show(box.Text)
Remember that case matters here.
Further saving this in a DB is out of scope for one question. There are as many ways to do that as there are programmers in the world. You should make your own attempt first, and come back here with a new question when you run into specific problems.
Thank you,
this is my attempt and it is done !
Dim userInput As TextBox = Form1.Controls.Item("TextBox" & i.ToString)
mycommand.Parameters.AddWithValue("#workstation", userInput.Text)
:D
Because you creating dynamic amount of input controls, right tool for the job will be DataGridView control.
Create a class to represent your data
Public Class LineInfo
Public Property Number As Integer
Public Property WorkStationNumber As Integer
End Class
Create `DataGridView in the form designer.
Private Sub btn_OK_lines_number_Click(sender As Object, e As EventArgs) Handles btn_OK_lines_number.Click
Dim linesAmount As Integer
If Integer.TryParse(txt_lines_number.Text, linesAmount) = False Then
MessageBox.Show("please enter a number")
txt_lines_number.Text = ""
Exit Sub
End If
' Create class instance for every line
Dim lines =
Enumerable.Range(1, linesAmount)
.Select(Function(i) New LineInfo With { .Number = i })
.ToList()
'Set lines as DataSource to the DataGridView
Me.DataGridView1.DataSource = lines
End Sub
DataGridView will display all lines and provide input fields to update work station numbers.
You can access updated lines later by casting DataSource back to the List
Dim lines = DirectCast(Me.DataGridView1.DataSource, List(Of LineInfo))
' Now you can access all data and save it to the database
Dim parameters =
lines.Select(Function(line)
Return new SqlParameter With
{
.ParameterName = $"#workstation{line.Number}",
.SqlDbType = SqlDbType.Int,
.Value = line.WorkStationNumber
}
End Function)
.ToList()
myCommand.Parameters.AddRange(parameters)
You can freely change style, font colors of different columns in the datagridview.

VB.net update list items from file

I click a button (with this code) to load lines from file "testexam" into a a listbox "lstHere". Testexam will be updated by another program and I want a code to copy new lines of "testexam" to the bottom of "lstHere". Secondly the selected index should come to the first item of the new list. Any help will be greatly appreciated.
Private Sub
Dim MReader As New StreamReader("C:\Users\Sparrow\testexam.txt")
Dim this1 As String = ""
Dim thisline(6000) As String
Dim i As Integer = 0
Do Until MReader.Peek = -1
this1= MReader.ReadLine
thisline(i)= this1
lstHere.Items.Add(thisline(i))
'go to the next line.
i = i + 1
Loop
End Sub
I don't know how you are trying to implement this, but it works with different buttons.
Button1:
'Add the selected item to the top
ListBox1.Items.Insert(0, ListBox1.SelectedIndex)
Button2:
'Delete duplicates
Dim items(ListBox1.Items.Count - 1) As Object
ListBox1.Items.CopyTo(items, 0)
ListBox1.Items.Clear()
ListBox1.Items.AddRange(items.AsEnumerable().Distinct().ToArray())

How to open the csv file with proper length in xl

Using VB.Net
Below code is working fine for creating a csv file.
When i open the csv file in xls or xlsx, some of the columns are collapsed, i need to expand manually to see the full details of the each column. I want to create a csv file with wraptext or length of the data
Code
Sub SetDataTable_To_CSV(ByVal dtable As DataTable, ByVal path_filename As String, ByVal sep_char As String)
Dim streamWriter As System.IO.StreamWriter
Try
streamWriter = New System.IO.StreamWriter(path_filename)
Dim _sep As String = ""
Dim builder As New System.Text.StringBuilder
For Each col As DataColumn In dtable.Columns
builder.Append(_sep).Append(col.ColumnName)
_sep = sep_char
Next
streamWriter.WriteLine(builder.ToString())
For Each row As DataRow In dtable.Rows
_sep = ""
builder = New System.Text.StringBuilder
For Each col As DataColumn In dtable.Columns
builder.Append(_sep).Append(row(col.ColumnName))
_sep = sep_char
Next
streamWriter.WriteLine(builder.ToString())
Next
Catch ex As Exception
Finally
If Not streamWriter Is Nothing Then streamWriter.Close()
End Try
End Sub
For Example
In csv file
12345,987665544433
Same File when i open in xl
12345,1.02141E+15
Expected Output
in xl file also
12345,987665544433
How to achieve this. Need code help
This behavior happens because of scientific notation which is a "feature" built into Excel. Unfortunately there is no known way to disable this, there are workarounds however:
1) If you want the numbers to show up properly without having to do anything then adding commas into your numbers is the way to go. Excel will still treat this as a number field, and will stop doing scientific notation on the number.
Note: You will most likely have to wrap all text in double-quotes to prevent Excel from thinking the commas indicate a new column. Wrapping your text with double quotes alone will not stop scientific notation from changing your numbers!:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim dt As New DataTable
dt.Columns.Add("StringField", GetType(String))
dt.Columns.Add("NumberField", GetType(String)) ' Notice that our number field is saved as type string so that we can add commas into the number
Dim dr As DataRow
For i As Int32 = 1 To 10
dr = dt.NewRow
dr("StringField") = "test"" " & i
dr("NumberField") = FormatNumber(987654320 + i, 0, TriState.UseDefault, TriState.UseDefault, TriState.True) ' Format the number with commas
dt.Rows.Add(dr)
Next
SetDataTable_To_CSV(dt, System.IO.Path.Combine(Application.StartupPath, "test.csv"), ",")
End Sub
Sub SetDataTable_To_CSV(ByVal dtable As DataTable, ByVal path_filename As String, ByVal sep_char As String)
Dim streamWriter As System.IO.StreamWriter
Try
streamWriter = New System.IO.StreamWriter(path_filename)
Dim _sep As String = ""
Dim builder As New System.Text.StringBuilder
For Each col As DataColumn In dtable.Columns
builder.Append(_sep).Append(FixCSVField(col.ColumnName)) ' Add quotes around this field
_sep = sep_char
Next
streamWriter.WriteLine(builder.ToString())
For Each row As DataRow In dtable.Rows
_sep = ""
builder = New System.Text.StringBuilder
For Each col As DataColumn In dtable.Columns
builder.Append(_sep).Append(FixCSVField(row(col.ColumnName))) ' Add quotes around this field
_sep = sep_char
Next
streamWriter.WriteLine(builder.ToString())
Next
Catch ex As Exception
Finally
If Not streamWriter Is Nothing Then streamWriter.Close()
End Try
End Sub
Function FixCSVField(sInString As String) As String
Return """" & sInString.Replace("""", """""""") & """" ' Wrap string in quotes to prevent problems with commas in the field and escape double quotes with another double quote
End Function
End Class
2) If you don't like the comma approach then you can always just open up the csv and highlight all the cells that you want to change. Once highlighted you can right-click on the columns and choose the "Format Cells" option. In the "Category" box, click "Number" and click "OK" to change all your cells back into numbers so that they no longer show up funny. Unfortunately this has to be done for every new csv file that you generate and I'm kind of assuming you knew about this option and were looking for the automatic method above.
3) The only last thing I can recommend is to use a different csv viewer such as Open Office or Google Spreadsheets to view your CSV files as these products do not truncate your numbers.
Good luck!
Edit:
I just thought of some more ideas on how to create your excel files automatically without any user intervention:
4) Use Excel Automation. You can use this to create an xls/xlsx file directly instead of a csv file. The benefit here is that you have a little more control of the data and layout then you do with a simple csv file. Unforunately there are many drawbacks and it depends upon your situation whether or not this is a valid option:
Potential Negatives:
You will require a license for Microsoft Excel on every machine your application will run on
All machines that the application runs on must have the same version of Microsoft Excel installed (For some reason I am thinking that newer versions installed on the client machine may still work, but older for sure will not, can anyone confirm?)
When you use Excel Automation, Microsoft Excel is loaded in the background which takes up memory to load a large number of files/DLLs
Excel Automation is much slower to generate large files as opposed to CSV
Microsoft explicitly recommends against using Excel Automation in a server environment: http://support.microsoft.com/kb/257757
That all being said, if you are just using the app on your own machine or you know for sure that everyone else who will use it is going to have the same version of Excel installed, this is a great way to write your Excel files without having to worry about the scientific notation problem.
Here is some sample code using the same test data as above:
Note: Before you can use this code you must add a reference to the Microsoft Excel xx.0 Object Library to your project. The version number will depend upon which version of Microsoft Excel you have installed on your machine. In my case I have Excel 2013 and therefore I add the Microsoft Excel 15.0 Object Library. You do this by opening up your project properties window, click the "References" tab, Click "Add", Click the "Com" tab and put a check next to the Microsoft Excel Object Library and click "OK".
Imports Microsoft.Office.Interop
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Test datatable creation
Dim dt As New DataTable
dt.Columns.Add("StringField", GetType(String))
dt.Columns.Add("NumberField", GetType(Int32)) ' Notice that our number field is now actually an integer type
Dim dr As DataRow
For i As Int32 = 1 To 10
dr = dt.NewRow
dr("StringField") = "test"" " & i
dr("NumberField") = 987654320 + i
dt.Rows.Add(dr)
Next
' Use Excel automation to create an xls/xlsx file
Dim xlApp As Excel.Application = New Microsoft.Office.Interop.Excel.Application()
If xlApp Is Nothing Then
' Excel automation can only be used if the correct version of excel is installed on the machine
MessageBox.Show("Excel is not installed on this computer.")
Else
Dim bIsXLSX As Boolean = True ' If this is true then an xlsx file is created, if false then the older xls file is used (use xls only if you need to support office 2003 and below)
Dim xlWorkBook As Excel.Workbook
Dim xlWorkSheet As Excel.Worksheet
Dim misValue As Object = System.Reflection.Missing.Value
Dim sFilename As String = System.IO.Path.Combine(Application.StartupPath, "excelfile.xls" & If(bIsXLSX = True, "x", ""))
xlWorkBook = xlApp.Workbooks.Add(misValue)
xlWorkSheet = xlWorkBook.Sheets("sheet1")
' Write headers
For c As Int32 = 0 To dt.Columns.Count - 1
xlWorkSheet.Cells(1, c + 1) = dt.Columns(c).ColumnName
Next
' Loop through rows and columns to create the data fields
For r As Int32 = 0 To dt.Rows.Count - 1
For c As Int32 = 0 To dt.Columns.Count - 1
xlWorkSheet.Cells(r + 2, c + 1) = dt.Rows(r).Item(c) ' Write the data to the correct column
Next
Next
xlWorkSheet.Columns.AutoFit() ' Autofit all cells to ensure they do not show the scientific notation
xlWorkBook.SaveAs(sFilename, If(bIsXLSX = True, Excel.XlFileFormat.xlWorkbookDefault, Excel.XlFileFormat.xlWorkbookNormal), misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue)
xlWorkBook.Close(True, misValue, misValue)
xlApp.Quit()
' Cleanup excel object
ReleaseExcelObject(xlWorkSheet)
ReleaseExcelObject(xlWorkBook)
ReleaseExcelObject(xlApp)
MessageBox.Show("Excel file created: " & sFilename)
End If
End Sub
Private Sub ReleaseExcelObject(ByVal oExcelObject As Object)
Try
System.Runtime.InteropServices.Marshal.ReleaseComObject(oExcelObject)
oExcelObject = Nothing
Catch ex As Exception
oExcelObject = Nothing
Finally
GC.Collect()
End Try
End Sub
End Class
5) If you would like to go the xls/xlsx route (as opposed to csv) but can't ensure that every client machine the app will be run on will have the same version of Excel installed you can use a third party dll to generate the file. The benefit of this approach is that the client machine does not even need to have Microsoft Excel installed to work. The biggest drawback to this method is that most dlls are not free.
There are many different options when it comes to these third party dlls so you have a lot of choices. Here are a few examples that should work for you:
Spire.XLS
GemBox.Spreadsheet
SpreadsheetGear
ComponentOne Excel for .Net
TMS Flexcel Studio for .NET
The only one I have used in the past is Spire.XLS and I will provide a working example below to demonstrate how easy it is to create the excel file with this dll. They provide a fully functional dll for free that you can use to test the product. The only limitation of using the free version versus paying is that the free version will automatically insert an extra worksheet into the file with an evaluation warning.
At the time of writing the newest version is 7.6 and you can find a direct link here: http://www.e-iceblue.com/downloads/spire.xls-se_7.6.zip (usually you need to signup to get the download link so this link may change in the future).
Here is a sample of how to get it working:
Imports Spire.Xls
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Test datatable creation
Dim dt As New DataTable
dt.Columns.Add("StringField", GetType(String))
dt.Columns.Add("NumberField", GetType(Int32)) ' Our number field is an actual integer this time
Dim dr As DataRow
For i As Int32 = 1 To 10
dr = dt.NewRow
dr("StringField") = "test"" " & i
dr("NumberField") = 987654320 + i
dt.Rows.Add(dr)
Next
' Use Spire.XLS to create an xls file
Dim bIsXLSX As Boolean = True ' If this is true then an xlsx file is created, if false then the older xls file is used (use xls only if you need to support office 2003 and below)
Dim sFilename As String = System.IO.Path.Combine(Application.StartupPath, "excelfile.xls" & If(bIsXLSX = True, "x", ""))
Dim oWorkbook As New Workbook
Dim oSheet As Worksheet = oWorkbook.Worksheets(0)
' New workbook automatically creates 3 blank worksheets by default
' Remove the last two since we only need one
oWorkbook.Worksheets.Remove(oWorkbook.Worksheets(2))
oWorkbook.Worksheets.Remove(oWorkbook.Worksheets(1))
' Write headers
For c As Int32 = 0 To dt.Columns.Count - 1
oSheet.Range(1, c + 1).Text = dt.Columns(c).ColumnName
Next
' Loop through rows and columns to create the data fields
For r As Int32 = 0 To dt.Rows.Count - 1
For c As Int32 = 0 To dt.Columns.Count - 1
oSheet.Range(r + 2, c + 1).Text = dt.Rows(r).Item(c) ' Write the data to the correct column
Next
Next
oSheet.Range().AutoFitColumns() ' Automatically adjust the width of all columns to fit the data
oWorkbook.SaveToFile(sFilename, If(bIsXLSX = True, ExcelVersion.Version2013, ExcelVersion.Version97to2003)) ' You can change version from 2013 to match the version of Excel you are using
oWorkbook.Dispose()
MessageBox.Show("Excel file created: " & sFilename)
End Sub
End Class
6) There is a free, open-source dll called ExcelLibrary that will create an xls file without having Excel installed but it hasn't been updated since 2011 and has a few quirks. First off it does not support the newer xlsx format, which shouldn't be an issue for you since you were using csv to begin with. Second, it supports setting the column width but it doesn't have an autofit option so you will have to hardcode the width which might cause the original problem with scientific notation if you don't specify a large enough width. Next, it does other funny things to large numbers like the ones you specified (ex. 987665544433) so you again have to treat the number as a string when you write it or else you will get negative numbers when they should be large positive numbers. Finally, xls files generated with this dll don't open properly in Microsoft Excel 2010 or higher unless it is of a certain filesize (file needs to be at least 7 KB in size so if you have too few rows the file won't open). However there is a workaround for this which involves adding blank data rows to the end of the file to make the filesize larger and therefore readable by Microsoft Excel. I don't recommend this approach because of all the quirks but I am including it for completion sake. Download the dll from here: https://code.google.com/p/excellibrary/
Imports ExcelLibrary.SpreadSheet
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Test datatable creation
Dim dt As New DataTable
dt.Columns.Add("StringField", GetType(String))
dt.Columns.Add("NumberField", GetType(String)) ' Our number field is a string value again, if you try Int32 it makes large numbers negative and if you try Int64 it will give you an "Invalid cell value" error
Dim dr As DataRow
For i As Int32 = 1 To 10
dr = dt.NewRow
dr("StringField") = "test"" " & i
dr("NumberField") = 987654320 + i
dt.Rows.Add(dr)
Next
' Use Excel Library to create an xls file
Dim sFilename As String = System.IO.Path.Combine(Application.StartupPath, "excelfile.xls")
Dim oWorkbook As New Workbook()
Dim oWorksheet As New Worksheet("Sheet1")
' Write headers
For c As Int32 = 0 To dt.Columns.Count - 1
oWorksheet.Cells(0, c) = New Cell(dt.Columns(c).ColumnName)
Next
' Loop through rows and columns to create the data fields
For r As Int32 = 0 To dt.Rows.Count - 1
For c As Int32 = 0 To dt.Columns.Count - 1
oWorksheet.Cells(r + 1, c) = New Cell(dt.Rows(r).Item(c)) ' Write the data to the correct column
Select Case c
Case Is = 0 ' StringField width
oWorksheet.Cells.ColumnWidth(c) = 3000
Case Is = 1 ' NumberField width
oWorksheet.Cells.ColumnWidth(c) = 3500
End Select
Next
Next
' Workaround to fix the "We found a problem with some content in 'excelfilename'" error when opening with Office 2010 or greater by adding extra blank rows to ensure the file size is greater than 7 KB
If dt.Rows.Count < 100 Then
Dim nRowCount = dt.Rows.Count + 1
Do While nRowCount < 100
oWorksheet.Cells(nRowCount, 0) = New Cell(" ")
nRowCount += 1
Loop
End If
oWorkbook.Worksheets.Add(oWorksheet)
oWorkbook.Save(sFilename)
MessageBox.Show("Excel file created: " & sFilename)
End Sub
End Class
As you can see there are many solutions to this problem. Please let us know which one worked for you!
Edit 2:
Well I had some more time and I found some better and FREE dlls to create xls/xlsx files with which are very much worth mentioning:
7) ClosedXML is a free, open source solution that can be used to create xlsx files from .Net code with much less hassle than ExcelLibrary. It only allows creation of the newer xlsx files so Excel 2007 or greater is required to open but it doesn't require Excel to be installed for it to create files. This one was really simple to use and the only real downside I found was that you need to also reference the DocumentFormat.OpenXml.dll (also free and open source) along with the ClosedXML dll. More information here: http://closedxml.codeplex.com/
Imports ClosedXML.Excel
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Test datatable creation
Dim dt As New DataTable
dt.Columns.Add("StringField", GetType(String))
dt.Columns.Add("NumberField", GetType(Int32)) ' Our number field is an actual integer this time
Dim dr As DataRow
For i As Int32 = 1 To 10
dr = dt.NewRow
dr("StringField") = "test"" " & i
dr("NumberField") = 987654320 + i
dt.Rows.Add(dr)
Next
' Use Closed XML to create an xlsx file
Dim sFilename As String = System.IO.Path.Combine(Application.StartupPath, "excelfile.xlsx")
Dim oWorkbook As New XLWorkbook
Dim oWorksheet = oWorkbook.Worksheets.Add("Sheet1")
' Write headers
For c As Int32 = 0 To dt.Columns.Count - 1
oWorksheet.Cell(1, c + 1).Value = dt.Columns(c).ColumnName
Next
' Loop through rows and columns to create the data fields
For r As Int32 = 0 To dt.Rows.Count - 1
For c As Int32 = 0 To dt.Columns.Count - 1
oWorksheet.Cell(r + 2, c + 1).Value = dt.Rows(r).Item(c) ' Write the data to the correct column
Next
Next
oWorksheet.Columns.AdjustToContents() ' Automatically adjust the width of all columns to fit the data
oWorkbook.SaveAs(sFilename)
oWorkbook.Dispose()
MessageBox.Show("Excel file created: " & sFilename)
End Sub
End Class
8) NPOI is another free open source dll that is a tad bit more complicated than ClosedXML but it supports read/write of xls, xlsx and word + powerpoint files too (not that you need those last ones). It also requires two dlls to be referenced and doesn't require excel to be installed to generate files. More information here: http://npoi.codeplex.com/
Imports NPOI.SS.UserModel
Imports NPOI.XSSF.UserModel
Imports NPOI.HSSF.UserModel
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Test datatable creation
Dim dt As New DataTable
dt.Columns.Add("StringField", GetType(String))
dt.Columns.Add("NumberField", GetType(Int32)) ' Our number field is an actual integer this time
Dim dr As DataRow
For i As Int32 = 1 To 10
dr = dt.NewRow
dr("StringField") = "test"" " & i
dr("NumberField") = 987654320 + i
dt.Rows.Add(dr)
Next
' Use NPOI to create an xls/xlsx file
Dim bIsXLSX As Boolean = True ' If this is true then an xlsx file is created, if false then the older xls file is used (use xls only if you need to support office 2003 and below)
Dim sFilename As String = System.IO.Path.Combine(Application.StartupPath, "excelfile.xls" & If(bIsXLSX = True, "x", ""))
Dim oWorkbook As IWorkbook
' Define workbook differently for xls and xlsx files
If bIsXLSX = True Then
oWorkbook = New XSSFWorkbook()
Else
oWorkbook = New HSSFWorkbook()
End If
Dim oWorksheet As ISheet = oWorkbook.CreateSheet("Sheet1")
Dim oRow As IRow
' Write headers
oRow = oWorksheet.CreateRow(0)
For c As Int32 = 0 To dt.Columns.Count - 1
oRow.CreateCell(c).SetCellValue(dt.Columns(c).ColumnName)
Next
' Loop through rows and columns to create the data fields
For r As Int32 = 0 To dt.Rows.Count - 1
oRow = oWorksheet.CreateRow(r + 1)
For c As Int32 = 0 To dt.Columns.Count - 1
oRow.CreateCell(c).SetCellValue(dt.Rows(r).Item(c).ToString) ' Write the data to the correct column
Next
Next
' Automatically adjust the width of all columns to fit the data
For i As Int32 = 0 To dt.Columns.Count - 1
oWorksheet.AutoSizeColumn(i)
Next
Dim sw As IO.FileStream = IO.File.Create(sFilename)
oWorkbook.Write(sw)
sw.Close()
MessageBox.Show("Excel file created: " & sFilename)
End Sub
End Class
9) Last but not least is EPPlus which again is free and open source. It only uses one dll and only works with xlsx files. Again, very simple to use. More information here: http://epplus.codeplex.com/
Imports OfficeOpenXml
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Test datatable creation
Dim dt As New DataTable
dt.Columns.Add("StringField", GetType(String))
dt.Columns.Add("NumberField", GetType(Int32)) ' Our number field is an actual integer this time
Dim dr As DataRow
For i As Int32 = 1 To 10
dr = dt.NewRow
dr("StringField") = "test"" " & i
dr("NumberField") = 987654320 + i
dt.Rows.Add(dr)
Next
' Use EPPlus to create an xlsx file
Dim sFilename As String = System.IO.Path.Combine(Application.StartupPath, "excelfile.xlsx")
Dim oPackage As New ExcelPackage()
Dim oWorksheet As ExcelWorksheet = oPackage.Workbook.Worksheets.Add("Sheet1")
' Write headers
For c As Int32 = 0 To dt.Columns.Count - 1
oWorksheet.Cells(1, c + 1).Value = dt.Columns(c).ColumnName
Next
' Loop through rows and columns to create the data fields
For r As Int32 = 0 To dt.Rows.Count - 1
For c As Int32 = 0 To dt.Columns.Count - 1
oWorksheet.Cells(r + 2, c + 1).Value = dt.Rows(r).Item(c).ToString ' Write the data to the correct column
Next
Next
oWorksheet.Cells(oWorksheet.Dimension.Address).AutoFitColumns() ' Automatically adjust the width of all columns to fit the data
oPackage.SaveAs(New IO.FileInfo(sFilename))
oPackage.Dispose()
MessageBox.Show("Excel file created: " & sFilename)
End Sub
End Class
Well that's it, I'm not adding more. Here are 9+ ways that you can accomplish what you are looking for using a variety of methods and complete with code examples. Believe it or not there are more ways to do this still but for sure one of these methods will get you to where you need to go. Happy coding!

updating textbox.text in a tabpage

I've got an app with numerous textboxes that's basically a form to fill out. There are several tabpages in a tab control. In saving the data, I simply loop through the textboxes, get their names and text and put that in a text file with a '|' as a seperator. That works great and I can see all my textboxes and the data in the text file. Now comes the problem. When I read the file back (to load saved data back into the form) it loops through the control name and changes the text to whatever was in the file. It works fine with the textboxes that are on the form, but fails when it gets to the first textbox that is on a tabpage. How can I fix that? And if there's a better way to save the data, I'm all ears.
Here's the code that writes the file:
Private Sub savefile(file As String)
Dim ctl As Control = Me
Dim sw As System.IO.StreamWriter
sw = My.Computer.FileSystem.OpenTextFileWriter(file, False)
Do
ctl = Me.GetNextControl(ctl, True)
If ctl IsNot Nothing Then
If TypeOf ctl Is TextBox Then
sw.WriteLine(ctl.Name.ToString.Substring(3) & "|" & ctl.Text)
End If
End If
Loop Until ctl Is Nothing
sw.Close()
End Sub
Here's the code that reads the file and updates the textboxes:
Private Sub ReadFile(filename)
Dim strfilename As String = filename
Dim num_rows, x, y As Integer
Dim strarray(1, 1) As String
Dim ctrl As Control = Me
'Check if file exist
If File.Exists(strfilename) Then
Dim tmpstream As StreamReader = File.OpenText(strfilename)
Dim strrecords() As String
Dim strfields() As String
'Load content of file to strLines array
strrecords = tmpstream.ReadToEnd().Split(vbCrLf)
' Redimension the array.
num_rows = UBound(strrecords)
ReDim strarray(num_rows, 2)
' Copy the data into the array.
For x = 0 To num_rows - 1
strfields = strrecords(x).Split("|")
For y = 0 To 1
strarray(x, y) = strfields(y)
Next
Next
' Display the data in listbox
For x = 0 To num_rows - 1
Dim tbxname As String = strarray(x, 0)
tbxname = Remove(tbxname) 'routine that removes invisible characters
tbxname = "tbx" & tbxname
MsgBox(tbxname) 'used to verify each file and which one fails
Me.Controls(tbxname).Text = strarray(x, 1)
Next
Else : MsgBox("File doesn't exist!")
End If
End Sub
I hope that's enough information. Thanks in advance for any help!!
I think the line Me.Controls(tbxname).text = strarray(x,1) does not address your TextBox in your tab control, you may need to find out how to address your textbox in the tab page.
Something like
Me.TabControl1.TabPages(0).Controls(tbxname).text = starray(x,1)