Getting OutOfRange exception when trying to insert values from datagridview into PDFtable - vb.net

I have a datagridview that I'm trying to export in pdf format. I downloaded and implemented a datagridviewtopdf class, but I needed to modify it to dynamically create the necessary columns (the column count will range from 1-12 for months in a year). I also needed to include an extra column to put the row header text for each row in my datagridview. I have the code, which I will include below. I keep getting an OutOfRange exception at the line that I've starred. Any idea how to fix this and create the pdf to resemble my datagridview table?
Edited to also include screenshots of datagridview. Datagridview will have up to 65 rows and up to 12 columns (not including rowheaders or columnheaders
Private Function GetDataTable() As System.Data.DataTable
Dim dataTable As New Data.DataTable("MyDataTable")
'Create another DataColumn Name
For column As Integer = 1 To DataGridView1.ColumnCount - 1
Dim dataColumn_1 As New DataColumn(DataGridView1.Columns(column).HeaderText.ToString(), GetType(String))
dataTable.Columns.Add(dataColumn_1)
'Now Add some row to newly created dataTable
Dim dataRow As DataRow
For i As Integer = 0 To DataGridView1.Rows.Count - 1
dataRow = dataTable.NewRow()
' Important you have create New row
dataRow(DataGridView1.Columns(column).HeaderText.ToString()) = DataGridView1.Rows(i).Cells(column).Value.ToString()
dataTable.Rows.Add(dataRow)
Next i
Next column
dataTable.AcceptChanges()
Return dataTable
End Function
Private Sub ExportDataToPDFTable()
Dim paragraph As New Paragraph
Dim doc As New Document(iTextSharp.text.PageSize.A4, 40, 40, 40, 10)
Dim wri As PdfWriter = PdfWriter.GetInstance(doc, New FileStream(SaveFileDialog1.FileName + ".pdf", FileMode.Create))
doc.Open()
Dim font12BoldRed As New iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.TIMES_ROMAN, 12.0F, iTextSharp.text.Font.UNDERLINE Or iTextSharp.text.Font.BOLDITALIC, BaseColor.RED)
Dim font12Bold As New iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.TIMES_ROMAN, 12.0F, iTextSharp.text.Font.BOLD, BaseColor.BLACK)
Dim font12Normal As New iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.TIMES_ROMAN, 12.0F, iTextSharp.text.Font.NORMAL, BaseColor.BLACK)
Dim p1 As New Phrase
p1 = New Phrase(New Chunk("PDF From Datagridview Data", font12BoldRed))
doc.Add(p1)
'Create instance of the pdf table and set the number of column in that table
Dim PdfTable As New PdfPTable(DataGridView1.ColumnCount + 1)
PdfTable.TotalWidth = 490.0F
'fix the absolute width of the table
PdfTable.LockedWidth = True
'relative col widths in proportions - 1,4,1,1 and 1
'Dim widths As Single() = New Single() {1.0F, 1.0F, 1.0F, 1.0F, 1.0F}
' PdfTable.SetWidths(widths)
PdfTable.HorizontalAlignment = 1 ' 0 --> Left, 1 --> Center, 2 --> Right
PdfTable.SpacingBefore = 2.0F
'pdfCell Decleration
Dim PdfPCell As PdfPCell = Nothing
'Assigning values to each cell as phrases
For column As Integer = 0 To (DataGridView1.ColumnCount - 1)
If column = 0 Then
For row As Integer = 0 To (DataGridView1.RowCount - 1)
'Getting out of range exception below for row
PdfPCell = New PdfPCell(New Phrase(New Chunk(DataGridView1.Rows(row).HeaderCell.ToString, font12Bold)))
'Add pdfcell in pdftable
PdfTable.AddCell(PdfPCell)
Next row
Else
PdfPCell = New PdfPCell(New Phrase(New Chunk(DataGridView1.Columns(column).HeaderText, font12Bold)))
'Alignment of phrase in the pdfcell
PdfPCell.HorizontalAlignment = PdfPCell.ALIGN_CENTER
'Add pdfcell in pdftable
PdfTable.AddCell(PdfPCell)
End If
Next column
Dim dt = GetDataTable()
If dt IsNot Nothing Then
'Now add the data from datatable to pdf table
For rows As Integer = 0 To dt.Rows.Count - 1
For column As Integer = 0 To dt.Columns.Count - 1
PdfPCell = New PdfPCell(New Phrase(dt.Rows(rows)(column).ToString(), font12Normal))
If column = 0 Or column = 1 Then
PdfPCell.HorizontalAlignment = PdfPCell.ALIGN_LEFT
Else
PdfPCell.HorizontalAlignment = PdfPCell.ALIGN_RIGHT
End If
PdfTable.AddCell(PdfPCell)
Next
Next
'Adding pdftable to the pdfdocument
doc.Add(PdfTable)
End If
doc.Close()
End Sub

Change:
For column As Integer = 1 To DataGridView1.ColumnCount + 1
For row As Integer = 1 To DataGridView1.RowCount
To:
For column As Integer = 0 To (DataGridView1.ColumnCount - 1)
For row As Integer = 0 To (DataGridView1.RowCount -1)
Remember: It's zero-base indexing.
Example:
Dim dtColumn As DataColumn
Dim dtRow As DataRow
For column As Integer = 0 To (Me.DataGridView1.ColumnCount - 1)
dtColumn = dt.Columns.Item(Me.DataGridView1.Columns(column).DataPropertyName)
For row As Integer = 0 To (DataGridView1.RowCount - 1)
dtRow = DirectCast(Me.DataGridView1.Rows(row).DataBoundItem, DataRowView).Row
'Replace this:
'PdfPCell = New PdfPCell(New Phrase(dt.Rows(rows)(column).ToString(), font12Normal))
'With this:
PdfPCell = New PdfPCell(New Phrase(row.Item(column).ToString(), font12Normal))
Next
Next

Related

Split output result by n and loop

I'm solving an issue where I need to create one PDF form.
That PDF form has 8 sections where I need to put info about and looks like shown on picture (only 4 shown).
The point is that my query will return 0 - n different results. So I need to split by 8 and post on different pages.
I tried like shown below but that seems not to work since I always load a new document. Does anyone have some advice how to make it?
Try
Dim sCommand As OleDb.OleDbCommand
sCommand = New OleDb.OleDbCommand("SELECT a,b,c Query to fetch n results ", _dbCon)
sCommand.CommandTimeout = 0
Dim _dbREADER As OleDb.OleDbDataReader
_dbREADER = sCommand.ExecuteReader
Dim dt As DataTable = New DataTable()
dt.Load(_dbREADER)
Dim totalPages As Integer = dt.Rows.Count / 8
Dim currentPage As Integer = 1
Dim rowCounter As Long = 0
If dt.Rows.Count > 0 Then
For Each row In dt.Rows
rowCounter += 1
If rowCounter = 8 Then
currentPage += 1
rowCounter = 0
End If
_pdfDocumentOutput = System.IO.Path.GetTempPath() & "MailingForm_" & currentPage & ".pdf"
SaveFromResources(_pdfDocument, My.Resources.template)
Using reader As New PdfReader(_pdfDocument)
Using stamper As New PdfStamper(reader, New IO.FileStream(_pdfDocumentOutput, IO.FileMode.Create))
Dim fontName As String = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "SCRIPTIN.ttf")
Dim bf As BaseFont = BaseFont.CreateFont(fontName, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED)
Dim pdfForm As AcroFields = stamper.AcroFields
pdfForm.AddSubstitutionFont(bf)
pdfForm.SetField(rowCounter - 1 & "0", row("Customer")) 'Checks the top radiobutton of the VrPr4 field
pdfForm.SetField(rowCounter - 1 & "1", row("Address"))
pdfForm.SetField(rowCounter - 1 & "2", row("Location"))
stamper.FormFlattening = True
End Using
End Using
Next
End If
Status.Text = "Store info loaded ! "
Catch ex As Exception
Status.Text = ex.Message
End Try
I found the solution by splitting tables
Private Shared Function SplitTable(ByVal originalTable As DataTable, ByVal batchSize As Integer) As List(Of DataTable)
Dim tables As List(Of DataTable) = New List(Of DataTable)()
Dim i As Integer = 0
Dim j As Integer = 1
Dim newDt As DataTable = originalTable.Clone()
newDt.TableName = "Table_" & j
newDt.Clear()
For Each row As DataRow In originalTable.Rows
Dim newRow As DataRow = newDt.NewRow()
newRow.ItemArray = row.ItemArray
newDt.Rows.Add(newRow)
i += 1
If i = batchSize Then
tables.Add(newDt)
j += 1
newDt = originalTable.Clone()
newDt.TableName = "Table_" & j
newDt.Clear()
i = 0
End If
If row.Equals(originalTable.Rows(originalTable.Rows.Count - 1)) Then
tables.Add(newDt)
j += 1
newDt = originalTable.Clone()
newDt.TableName = "Table_" & j
newDt.Clear()
i = 0
End If
Next
Return tables
End Function
And after that loop through each one of table . And put all results to one file
Dim tables = SplitTable(dt, 8)

Adding row in DataTable

I'm doing a project in vb and I'm trying to add all the rows in dataTable name dt to a new dataTable name dtNew but i dont want duplicate rows to be added in dtNew instead adding the count if its duplicate. someone help me please.
here is a sample dataTable name dt as you can see apple is duplicate
here is my code.
Dim dtNew As DataTable = New DataTable '---> I Created new DataTable
'---> Created 3 columns
dtNew.Columns.Add("TYPE", Type.GetType("System.String"))
dtNew.Columns.Add("NAME", Type.GetType("System.String"))
dtNew.Columns.Add("COUNT", Type.GetType("System.Int32"))
For Each dtRow As DataRow In dt.Rows ' ---> loop all the rows in dt DataTable
Dim newRow As DataRow = dtNew.NewRow
newRow("TYPE") = dtRow("TYPE")
newRow("NAME") = dtRow("NAME")
newRow("COUNT") = dtRow("COUNT")
'check if dtNew DataTable has no row
If Not dtNew Is Nothing AndAlso dtNew.Rows.Count = 0 Then
'add new row
dtNew.Rows.Add(newRow)
Else
' I want to check first all the rows in dtNew DataTable
' if its existed, and if it's not then add new row
For Each dtNewRow As DataRow In dtNew.Rows
If ((dtNewRow("TYPE") = "VEGETABLE" OrElse _
dtNewRow("TYPE") = "FRUIT") And _
dtNewRow("NAME") <> newRow("NAME")) Then
'insert row
dtNew.Rows.InsertAt(newRow, dtNew.Rows.Count)
'error: Collection was modified; enumeration operation might not be executed.
End If
Next
End If
Next
For Each row As DataRow In dt.Rows
Dim type = CStr(row("Type"))
Dim name = CStr(row("Name"))
Dim existingRows = dtNew.Select(String.Format("Type = '{0}' AND Name = '{1}'",
type,
name))
If existingRows.Length = 0 Then
'No match so create a new row.
Dim newRow = dtNew.NewRow()
newRow("Type") = type
newRow("Name") = name
newRow("Count") = row("Count")
dtNew.Rows.Add(newRow)
Else
'Match found so update existing row.
Dim newRow = existingRows(0)
newRow("Count") = CInt(newRow("Count")) + CInt(row("Count"))
End If
Next
As the tables have the same schema, you could even simplify the If block to this:
dtNew.ImportRow(row)
That would only be a problem if row had a RowState other than Unchanged and you didn't want to import that too.

VB: Count number of columns in csv

So, quite simple.
I am importing CSVs into a datagrid, though the csv always has to have a variable amount of columns.
For 3 Columns, I use this code:
Dim sr As New IO.StreamReader("E:\test.txt")
Dim dt As New DataTable
Dim newline() As String = sr.ReadLine.Split(";"c)
dt.Columns.AddRange({New DataColumn(newline(0)), _
New DataColumn(newline(1)), _
New DataColumn(newline(2))})
While (Not sr.EndOfStream)
newline = sr.ReadLine.Split(";"c)
Dim newrow As DataRow = dt.NewRow
newrow.ItemArray = {newline(0), newline(1), newline(2)}
dt.Rows.Add(newrow)
End While
DG1.DataSource = dt
This works perfectly. But how do I count the number of "newline"s ?
Can I issue a count on the number of newlines somehow? Any other example code doesn't issue column heads.
If my csv file has 5 columns, I would need an Addrange of 5 instead of 3 and so on..
Thanks in advance
Dim sr As New IO.StreamReader(path)
Dim dt As New DataTable
Dim newline() As String = sr.ReadLine.Split(","c)
' MsgBox(newline.Count)
' dt.Columns.AddRange({New DataColumn(newline(0)),
' New DataColumn(newline(1)),
' New DataColumn(newline(2))})
Dim i As Integer
For i = 0 To newline.Count - 1
dt.Columns.AddRange({New DataColumn(newline(i))})
Next
While (Not sr.EndOfStream)
newline = sr.ReadLine.Split(","c)
Dim newrow As DataRow = dt.NewRow
newrow.ItemArray = {newline(0), newline(1)}
dt.Rows.Add(newrow)
End While
dgv.DataSource = dt
End Sub
Columns and item values can be added to a DataTable individually, using dt.Columns.Add and newrow.Item, so that these can be done in a loop instead of hard-coding for a specific number of columns. e.g. (this code assumes Option Infer On, so adjust as needed):
Public Function CsvToDataTable(csvName As String, Optional delimiter As Char = ","c) As DataTable
Dim dt = New DataTable()
For Each line In File.ReadLines(csvName)
If dt.Columns.Count = 0 Then
For Each part In line.Split({delimiter})
dt.Columns.Add(New DataColumn(part))
Next
Else
Dim row = dt.NewRow()
Dim parts = line.Split({delimiter})
For i = 0 To parts.Length - 1
row(i) = parts(i)
Next
dt.Rows.Add(row)
End If
Next
Return dt
End Function
You could then use it like:
Dim dt = CsvToDataTable("E:\test.txt", ";"c)
DG1.DataSource = dt

error Public member 'Value' on type 'Integer' not found. exporting data to excel from datagridview including images

I have a datagrid which has two image column. I want to export the data to excel. And using this code
SaveFileDialog1.Filter = "Excel Files (*.xlsx*)|*.xlsx"
SaveFileDialog1.ShowDialog()
Dim filename As String = SaveFileDialog1.FileName
'verfying the datagridview having data or not
If ((DataGridView1.Columns.Count = 0) Or (DataGridView1.Rows.Count = 0)) Then
Exit Sub
End If
'Creating dataset to export
Dim dset As New DataSet
'add table to dataset
dset.Tables.Add()
'add column to that table
For i As Integer = 0 To DataGridView1.ColumnCount - 1
dset.Tables(0).Columns.Add(DataGridView1.Columns(i).HeaderText)
Next
'add rows to the table
Dim dr1 As DataRow
For i As Integer = 0 To DataGridView1.RowCount - 1
dr1 = dset.Tables(0).NewRow
For j As Integer = 0 To DataGridView1.Columns.Count - 1
Dim cj = DataGridView1.Rows(i).Cells(j).Value
If (cj.GetType = GetType(Byte())) Then
'Error = Publicmember 'Value' on type 'Integer' not found.
Dim data As Byte() = DirectCast(cj.Value, Byte())
Dim ms As New System.IO.MemoryStream(data)
Dim k As System.Drawing.Image = System.Drawing.Image.FromStream(ms)
dr1(j) = k
Else
dr1(j) = DataGridView1.Rows(i).Cells(j).Value
End If
Next
dset.Tables(0).Rows.Add(dr1)
Next
Dim excel As New Excel.Application()
Dim wBook As Microsoft.Office.Interop.Excel.Workbook
Dim wSheet As Microsoft.Office.Interop.Excel.Worksheet
wBook = excel.Workbooks.Add()
wSheet = wBook.ActiveSheet()
Dim dt As System.Data.DataTable = dset.Tables(0)
Dim dc As System.Data.DataColumn
Dim dr As System.Data.DataRow
Dim colIndex As Integer = 0
Dim rowIndex As Integer = 0
For Each dc In dt.Columns
colIndex = colIndex + 1
excel.Cells(1, colIndex) = dc.ColumnName
Next
For Each dr In dt.Rows
rowIndex = rowIndex + 1
colIndex = 0
For Each dc In dt.Columns
colIndex = colIndex + 1
excel.Cells(rowIndex + 1, colIndex) = dr(dc.ColumnName)
Next
Next
wSheet.Columns.AutoFit()
Dim strFileName As String = filename
Dim blnFileOpen As Boolean = False
Try
Dim fileTemp As System.IO.FileStream = System.IO.File.OpenWrite(strFileName)
fileTemp.Close()
Catch ex As Exception
blnFileOpen = False
End Try
If System.IO.File.Exists(strFileName) Then
System.IO.File.Delete(strFileName)
End If
wBook.SaveAs(strFileName)
excel.Workbooks.Open(strFileName)
excel.Visible = True
It is giving me error Public member 'Value' on type 'Integer' not found. Though this condition works with itextsharp i mean for PDF creation time. please help me. if remove that condition and run the code then it will create an excel file with image column as 'System.Byte[]'.
I get the feeling that you think that you're storing the grid cell in cj and then getting the Value of that cell but you have actually already got the Value of the cell and put that into cj. Get rid of the Value property access on the following line and your code will likely work:
Dim cj = DataGridView1.Rows(i).Cells(j).Value
By the way, don't do this:
If (cj.Value.GetType = GetType(Byte())) Then
It would be preferable to do this in isolation:
If TypeOf cj.Value Is Byte() Then
but, given that you're going to cast as that type if it is then you should use TryCast instead:
Dim data As Byte() = TryCast(cj.Value, Byte())
If data IsNot Nothing Then
'Use data here.
End If
TryCast is like DirectCast except that it returns Nothing if the cast fails rather than throwing an exception.

Error while trying to export DataGridView as pdf

I'm trying to export a populated datagridview with the following code:
Imports System.Data.OleDb
Imports Microsoft.Office.Interop.Excel
Imports System.Drawing
Imports DGVPrinterHelper
Imports iTextSharp
Imports iTextSharp.text.pdf
Imports iTextSharp.text
Imports System.Data.Odbc
Imports System.IO
Private Sub Export_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
SaveFileDialog1.ShowDialog()
If SaveFileDialog1.FileName = "" Then
MsgBox("Enter Filename to create PDF")
Exit Sub
Else
ExportDataToPDFTable()
MsgBox("PDF Created Successfully")
End If
End Sub
Private Function GetDataTable() As DataTable
Dim dataTable As New Data.DataTable("MyDataTable")
'Create another DataColumn Name
For column As Integer = 1 To DataGridView1.ColumnCount - 1
Dim dataColumn_1 As New DataColumn(DataGridView1.Columns(column).HeaderText.ToString(), GetType(String))
dataTable.Columns.Add(dataColumn_1)
'Now Add some row to newly created dataTable
Dim dataRow As DataRow
For i As Integer = 0 To DataGridView1.Rows.Count - 1
dataRow = dataTable.NewRow()
' Important you have create New row
dataRow(DataGridView1.Columns(column).HeaderText.ToString()) = DataGridView1.Rows(i).Cells(column).Value.ToString()
dataTable.Rows.Add(dataRow)
Next i
Next column
dataTable.AcceptChanges()
Return dataTable
End Function
Private Sub ExportDataToPDFTable()
Dim paragraph As New Paragraph
Dim doc As New Document(iTextSharp.text.PageSize.A4, 40, 40, 40, 10)
Dim wri As PdfWriter = PdfWriter.GetInstance(doc, New FileStream(SaveFileDialog1.FileName + ".pdf", FileMode.Create))
doc.Open()
Dim font12BoldRed As New iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.TIMES_ROMAN, 12.0F, iTextSharp.text.Font.UNDERLINE Or iTextSharp.text.Font.BOLDITALIC, BaseColor.RED)
Dim font12Bold As New iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.TIMES_ROMAN, 12.0F, iTextSharp.text.Font.BOLD, BaseColor.BLACK)
Dim font12Normal As New iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.TIMES_ROMAN, 12.0F, iTextSharp.text.Font.NORMAL, BaseColor.BLACK)
Dim p1 As New Phrase
p1 = New Phrase(New Chunk("PDF From Datagridview Data", font12BoldRed))
doc.Add(p1)
'Create instance of the pdf table and set the number of column in that table
Dim PdfTable As New PdfPTable(5)
PdfTable.TotalWidth = 490.0F
'fix the absolute width of the table
PdfTable.LockedWidth = True
'relative col widths in proportions - 1,4,1,1 and 1
Dim widths As Single() = New Single() {1.0F, 4.0F, 1.0F, 1.0F, 1.0F}
PdfTable.SetWidths(widths)
PdfTable.HorizontalAlignment = 1 ' 0 --> Left, 1 --> Center, 2 --> Right
PdfTable.SpacingBefore = 2.0F
'pdfCell Decleration
Dim PdfPCell As PdfPCell = Nothing
'Assigning values to each cell as phrases
PdfPCell = New PdfPCell(New Phrase(New Chunk("Taxcode", font12Bold)))
'Alignment of phrase in the pdfcell
PdfPCell.HorizontalAlignment = PdfPCell.ALIGN_CENTER
'Add pdfcell in pdftable
PdfTable.AddCell(PdfPCell)
PdfPCell = New PdfPCell(New Phrase(New Chunk("Tax Name", font12Bold)))
PdfPCell.HorizontalAlignment = PdfPCell.ALIGN_CENTER
PdfTable.AddCell(PdfPCell)
PdfPCell = New PdfPCell(New Phrase(New Chunk("Cess Tax", font12Bold)))
PdfPCell.HorizontalAlignment = PdfPCell.ALIGN_CENTER
PdfTable.AddCell(PdfPCell)
PdfPCell = New PdfPCell(New Phrase(New Chunk("Sales Tax", font12Bold)))
PdfPCell.HorizontalAlignment = PdfPCell.ALIGN_CENTER
PdfTable.AddCell(PdfPCell)
PdfPCell = New PdfPCell(New Phrase(New Chunk("Other Tax", font12Bold)))
PdfPCell.HorizontalAlignment = PdfPCell.ALIGN_CENTER
PdfTable.AddCell(PdfPCell)
Dim dt As DataTable = GetDataTable()
If dt IsNot Nothing Then
'Now add the data from datatable to pdf table
For rows As Integer = 0 To dt.Rows.Count - 1
For column As Integer = 0 To dt.Columns.Count - 1
PdfPCell = New PdfPCell(New Phrase(dt.Rows(rows)(column).ToString(), font12Normal))
If column = 0 Or column = 1 Then
PdfPCell.HorizontalAlignment = PdfPCell.ALIGN_LEFT
Else
PdfPCell.HorizontalAlignment = PdfPCell.ALIGN_RIGHT
End If
PdfTable.AddCell(PdfPCell)
Next
Next
'Adding pdftable to the pdfdocument
doc.Add(PdfTable)
End If
doc.Close()
End Sub
When I run the program a click the button it prompts me with the SaveFileDialog, but once I click save I get the error "Unable to cast object of type 'System.Data.DataTable' to type 'Microsoft.Office.Interop.Excel.DataTable'." at the "Return dataTable" line in the Private Function GetDataTable(). Can anyone help me resolve this issue? And please feel free to point out other errors with my code (if there are any)