Printing multiple pages from an ArrayList - vb.net

First let me start off with I am not a vb.net developer. In fact I have never been trained in the art of VB. That being said I am working on a very simple application that takes a csv file and parses a single column to an array list. Now i need to take that array list and print a individual page (Without preview) of each item on the array list. So each item on the array list will have its own page.
Heres what i have so far. Im sure Im way off seeing as I cant figure out how to turn this into multi-pages.
Private Sub Print()
Dim PrintPreviewSelected As Boolean = False
'Set the doc to print
Dim pDoc As New PrintDocument
pDoc.PrintController = New StandardPrintController 'turns off the printing page x of y dialog
Try
Using sr As New StreamReader(file)
defPrinter = sr.ReadToEnd()
End Using
Catch e As Exception
End Try
If defPrinter = "" Then
If Me.PrintDialog1.ShowDialog() = DialogResult.OK Then
pDoc.PrinterSettings.PrinterName = Me.PrintDialog1.PrinterSettings.PrinterName
End If
Else
pDoc.PrinterSettings.PrinterName = defPrinter
End If
pDoc.DefaultPageSettings.Landscape = True
pDoc.DefaultPageSettings.Margins = New Margins(40, 10, 10, 10)
pDoc.OriginAtMargins = True
AddHandler pDoc.PrintPage, AddressOf PrintSett
If PrintPreviewSelected Then
PrintPreviewDialog1.Document = pDoc
PrintPreviewDialog1.UseAntiAlias = True
PrintPreviewDialog1.WindowState = FormWindowState.Maximized
PrintPreviewDialog1.ShowDialog()
Else
If txtFile.Text <> "" Then
pDoc.Print()
Else
MessageBox.Show("You must select a file first", "Select a file.")
End If
End If
RemoveHandler pDoc.PrintPage, AddressOf PrintSett
End Sub
Private Sub PrintSett(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs)
Dim fnt10 As Font = New Font("Courier New", 34, FontStyle.Regular)
e.Graphics.DrawString("", fnt10, Brushes.Black, 318, 412)
End Sub
Any help would be appreciated! I know i havent laid any of the foundation for you guys to work off of but frankly Im strait up lost. Thanks guys!

Following matzone's suggestion I was able to figure it out.
Dim PageNumber As Integer = 1
Dim morePage As String
Private Sub PrintSett(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs)
Dim ReportFont As New Font("Arial", 45, FontStyle.Regular)
Dim VerticalPrintLocationSingle As Single = 412
Dim HorizontalPrintLocationSingle As Single = e.MarginBounds.Left
Dim TextString As String
Dim sngCenterPage As Single
If customerList.Count > (PageNumber) Then
If customerList.Item(PageNumber) IsNot "" Then
TextString = customerList.Item(PageNumber)
Console.WriteLine(customerList.Item(PageNumber))
sngCenterPage = Convert.ToSingle(e.PageBounds.Width / 2 - e.Graphics.MeasureString(customerList.Item(PageNumber), ReportFont).Width / 2)
PageNumber += 1
morePage = True
End If
Else
morePage = False
customerList.Clear()
End If
e.Graphics.DrawString(TextString, ReportFont, Brushes.Black, sngCenterPage, VerticalPrintLocationSingle)
e.HasMorePages = morePage
End Sub
Thanks again!

Related

Threading doesn't complete the task before ending the thread loop

So I did something similar a while ago, but this is essentially a username checker for a (specific) website, they can load in usernames via text file and it will put it into a list box, now I have the start button and it's meant to check each username. Before, however, it froze the program when they checked, but it worked. I tried making it "threaded" so it didn't freeze.
The problem now is that it doesn't check them all, and finishes instantly.
CODE:
Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
Button6.Enabled = False
Dim goodUsers As New SaveFileDialog()
goodUsers.Filter = "TXT file (*.txt)|*.txt"
Dim flag As Boolean
Dim Incomplete As Integer = 0
Dim Taken As Integer = 0
Dim sb As New StringBuilder
If goodUsers.ShowDialog() = DialogResult.OK Then
Dim checkerMT As New Thread(
Sub()
For Each i As String In UsernameList.Items
WebRequest.Create("http://yatobooter.cf/other/checkusr.php?username=" + i.ToString)
Dim cResult As String = New System.Net.WebClient().DownloadString("http://yatobooter.cf/other/checkusr.php?username=" + i.ToString).ToString
If cResult = "taken" Then
flag = False
ElseIf cResult = "nottaken" Then
flag = True
End If
If flag = True Then
sb.Append(i & vbNewLine)
Else
Incomplete = Incomplete + 1
Taken = UsernameList.Items.Count - Incomplete
End If
Next
End Sub
)
checkerMT.Start()
Try
File.WriteAllText(goodUsers.FileName, sb.ToString)
Catch ex As Exception
Exit Sub
End Try
End If
MessageBox.Show("Checking available usernames, complete!", "NameSniper Pro")
Button6.Enabled = True
End Sub
You cannot access UI elements (UsernameList.Items) from a thread other than the UI. Instead add a background worker to your form to handle the basic threading stuff (progress reporting, finish reporting, exception handling). Pass into this an object that contains the settings your job needs to do its work without interacting with the ui.
Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
Button6.Enabled = False
Dim goodUsers As New SaveFileDialog()
goodUsers.Filter = "TXT file (*.txt)|*.txt"
If goodUsers.ShowDialog() = DialogResult.OK Then
'Note: You'll need to add the filenames
BackgroundWorker1.RunWorkerAsync(New State() With {.Names = {}, .FileName = goodUsers.FileName})
End If
End Sub
Class State
Public Names As List(Of String)
Public StringBuilder As New System.Text.StringBuilder
Public Incomplete As Integer
Public Taken As Integer
Public FileName As String
End Class
Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim state = CType(e.Argument, State)
For Each i As String In state.Names
Using cli = New System.Net.WebClient()
Dim cResult = cli.DownloadString("http://yatobooter.cf/other/checkusr.php?username=" + i.ToString).ToString
If cResult = "nottaken" Then
state.StringBuilder.Append(i & vbNewLine)
Else
state.Incomplete = state.Incomplete + 1
state.Taken = state.Names.Count - state.Incomplete
End If
End Using
Next
IO.File.WriteAllText(state.FileName, state.StringBuilder.ToString)
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If e.Error IsNot Nothing Then
MessageBox.Show(e.Error.ToString(), "Error")
Else
MessageBox.Show("Checking available usernames, complete!", "NameSniper Pro")
End If
Button6.Enabled = True
End Sub
The SaveFileDialog can be used as "Using directive"
Why do you create a webrequest on the one hand, and on the other hand use a webclient? That does not make sense at all.
Instead of your strange if condition, write:
flag = (cResult.Equals("nottaken"))
All code you want to run after the actions you are currently running in your thread have to be in your thread as well, because it is async.
You have to invoke if you use user controls within a thread
and so on..
Please turn Option Strict On and Option Infer Off
There are lots of other things you could do better.
Please remove the webrequest and webclient combination yourself, that does not make sense at all.
Take a look at this, I cleared it a little bit:
Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
Dim Incomplete As Integer = 0
Dim Taken As Integer = 0
Dim sb As New StringBuilder
Using goodUsers As SaveFileDialog = new SaveFileDialog()
goodUsers.Filter = "TXT file (*.txt)|*.txt"
If not goodUsers.ShowDialog() = DialogResult.OK Then Exit Sub
Dim checkerMT As New Thread(
Sub()
Me.invoke(sub()
Button6.Enabled = False
For Each i As String In UsernameList.Items
WebRequest.Create("http://yatobooter.cf/other/checkusr.php?username=" + i.ToString)
Dim cResult As String = New System.Net.WebClient().DownloadString("http://yatobooter.cf/other/checkusr.php?username=" + i.ToString).ToString
If (cResult.toLower().Equals("nottaken")) Then
sb.Append(String.Concat(i , Environment.NewLine)
Else
Incomplete += 1
Taken = UsernameList.Items.Count - Incomplete
End If
Next
File.WriteAllText(goodUsers.FileName, sb.ToString)
Button6.Enabled = True
MessageBox.Show("Checking available usernames, complete!", "NameSniper Pro")
End Sub)
End Sub
)
checkerMT.IsBackground = True;
checkerMT.Start()
End Sub

Datagridview strange display error on init

upon initialization of my UI i get the following very strange behavior regarding to the drawing of the datagridview:
Basically, expect the first row header and the column headers (which i did not include in the pic) it looks like the DGV prints what is on the Screen "behind" his application.
What the hell is this and does anyone know a way to fix it?
Code of Container:
Public Class DGVControl
Dim dt As DataTable
Public Sub init()
dt = New DataTable
Dim arr(ldfAttributes.Count - 1) As String
Dim cms As New ContextMenuStrip
Dim i As Integer = 0
For Each att As String In Attributes.Keys
Dim cmsitem As New ToolStripMenuItem
dt.Columns.Add(att, GetType(String))
cmsitem.Name = att
cmsitem.Text = att
cmsitem.Owner = cms
cmsitem.CheckOnClick = True
cmsitem.Checked = my.Settings.shownColumns.Contains(att)
AddHandler cmsitem.CheckedChanged, AddressOf showOrHideColumn
cms.Items.Add(cmsitem)
arr(i) = "No Data"
i += 1
Next
For i = 1 To my.settings.anzEntries
dt.Rows.Add(arr)
Next
MainDGV.DataSource = dt
MainDGV.ContextMenuStrip = cms
For Each attName as String In Attributes.key
showOrHideColumn(cms.Items(attName), New EventArgs())
Next
MainDGV.RowHeadersWidth = 90
MainDGV.RowTemplate.Height = 40
MainDGV.RowHeadersDefaultCellStyle.BackColor = Color.White
MainDGV.RowHeadersDefaultCellStyle.Font = New Font(MainDGV.ColumnHeadersDefaultCellStyle.Font, FontStyle.Bold)
MainDGV.ColumnHeadersDefaultCellStyle.BackColor = Color.White
MainDGV.ColumnHeadersDefaultCellStyle.Font = New Font(MainDGV.ColumnHeadersDefaultCellStyle.Font, FontStyle.Bold)
MainDGV.BackgroundColor = Color.White
End Sub
Private Sub showOrHideColumn(sender As Object, e As EventArgs)
Dim cmsitem As ToolStripMenuItem = CType(sender, ToolStripMenuItem)
MainDGV.Columns(cmsitem.Name).Visible = cmsitem.Checked
End Sub
'taken from: http://stackoverflow.com/questions/710064/adding-text-to-datagridview-row-header
Private Sub nameRowHeaders(sender As Object, e As EventArgs) Handles MainDGV.DataBindingComplete
Dim dgv As DataGridView = CType(sender, DataGridView)
For i As Integer = 0 To dgv.RowCount - 1
dgv.Rows(i).HeaderCell.Value = ("Entry " &(i+1).toString())
Next
End Sub
End Class
EDIT:
As soon as you once select a row, all cells will be displayed in the right way until you restart the application

VB.Net Process.CloseMainWindow and Process.Close not working

I've used a background worker to launch an application, wait for cancellation and then close the application. But for some reason the application never closes. I've tried with and without notificationPreview.WaitForExit()
Private Sub bgWorker_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bgWorker.DoWork
'Extract the executable to the applications directory path and execute it
Dim notificationPreview As New Process
Dim monitorExe As Byte() = My.Resources.ITSupportMonitoring
My.Computer.FileSystem.WriteAllBytes(My.Application.Info.DirectoryPath & "ITSupportMonitoring.exe", monitorExe, False)
notificationPreview = Process.Start(My.Application.Info.DirectoryPath & "ITSupportMonitoring.exe")
notificationPreview.WaitForInputIdle()
'Wait until the worker is sent a cancellation request
Do Until bgWorker.CancellationPending = True
System.Threading.Thread.Sleep(500)
Loop
'If the process hasn't been closed by the user close it
If Not notificationPreview.HasExited Then 'If the process is still running
notificationPreview.CloseMainWindow() 'Tell the main window of the notification process to close
notificationPreview.WaitForExit()
notificationPreview.Close() 'Free all resources used by the notification process
End If
My.Computer.FileSystem.DeleteFile(My.Application.Info.DirectoryPath & "ITSupportMonitoring.exe") 'Delete the executable file
e.Cancel = True
End Sub
Here is the FULL code for the process which will not close:
Public Class frmMonitoring
Dim noticeText As String
Private Sub frmMonitoring_Load(sender As Object, e As EventArgs) Handles Me.Load
'Set the notice text
If My.Application.CommandLineArgs.Count > 0 Then
noticeText = My.Application.CommandLineArgs(0)
Else
noticeText = "Example String"
End If
Me.ForeColor = Color.Black
tmrFlash.Interval = 1000
tmrFlash.Start()
Me.Top = 0
Me.Left = 0
Me.TopMost = True
End Sub
Private Sub tmrFlash_Tick(sender As Object, e As EventArgs) Handles tmrFlash.Tick
If Me.ForeColor = Color.Black Then
Me.ForeColor = Color.Red
Else
Me.ForeColor = Color.Black
End If
End Sub
Protected Overrides Sub OnPaint(e As PaintEventArgs)
MyBase.OnPaint(e)
Dim drawFont As New System.Drawing.Font(SystemFonts.DefaultFont.Name, 16)
Dim drawBrush As New System.Drawing.SolidBrush(Me.ForeColor)
Dim drawFormat As New System.Drawing.StringFormat
Dim drawRect As New RectangleF(e.ClipRectangle.Location, e.ClipRectangle.Size)
drawRect.Height = drawRect.Height * 0.65 'The bottom line of text was getting partially clipped, so reduced the height of the drawing area to 65%
drawFont = GetAdjustedFont(e.Graphics, noticeText, drawFont, drawRect, 40, 4, True)
Dim stringFormat As New StringFormat(StringFormatFlags.NoClip)
stringFormat.Alignment = StringAlignment.Center
stringFormat.LineAlignment = StringAlignment.Center
e.Graphics.DrawString(noticeText, drawFont, drawBrush, RectangleF.op_Implicit(ClientRectangle), stringFormat)
drawFont.Dispose()
drawBrush.Dispose()
End Sub
Public Function GetAdjustedFont(ByRef GraphicRef As Graphics, ByVal GraphicString As String, ByVal OriginalFont As Font, ByVal ContainerSize As RectangleF, ByVal MaxFontSize As Integer, ByVal MinFontSize As Integer, ByVal SmallestOnFail As Boolean) As Font
'Loop through font sizes and MeasureString to find the largest font which can be used
For AdjustedSize As Integer = MaxFontSize To MinFontSize Step -1
Dim TestFont = New Font(OriginalFont.Name, AdjustedSize, OriginalFont.Style)
Dim charsFitted As Integer
Dim linesFilled As Integer
' Test the string with the new size
Dim AdjustedSizeNew = GraphicRef.MeasureString(GraphicString, TestFont, ContainerSize.Size, New StringFormat, charsFitted, linesFilled)
If charsFitted = GraphicString.Length Then 'If every characted in the string was printed
'Good font, return it
Return TestFont 'New Font(TestFont.Name, TestFont.Size - 1, TestFont.Style)
End If
Next
' If you get here there was no fontsize that worked
' return MinimumSize or Original?
If SmallestOnFail Then
Return New Font(OriginalFont.Name, MinFontSize, OriginalFont.Style)
Else
Return OriginalFont
End If
End Function
End Class

Alternate between hiding and showing different controls on form

I'm working on a small project to dynamically add browsers to a form and alternate them on a timer so every tick one browser changes from visible=true to false and so on, but can't for the life of me figure out how to do it.
'Some Variables
Dim Browsers() As WebControl
Dim XMLFile As String = "\\********.xml"
Dim Controllist As New ArrayList
Dim BrowserCount As Integer
Private Sub Left_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Set form properties
Me.Location = New Point(Screen.AllScreens(0).Bounds.X, Screen.AllScreens(0).Bounds.Y)
Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
Me.WindowState = FormWindowState.Maximized
Me.TopMost = True
Try
'Load xml file with urls
Dim xmlDoc As New XmlDocument
Dim nodeList As XmlNodeList = xmlDoc.SelectNodes("//BottomLeft/url")
xmlDoc.Load(XMLFile)
'Define number of browsers based on xml
Dim numberOfBrowsers As Integer = nodeList.Count + 1
ReDim Browsers(numberOfBrowsers)
'Put urls in an array to use later
Dim UrlList As New ArrayList
Debug.WriteLine("Number of browser is: " & numberOfBrowsers)
For Each inst As XmlNode In nodeList
UrlList.Add(inst.InnerText)
Debug.WriteLine("Added to array: " & inst.InnerText)
Next
'Set properties and add the browsers
For counter As Integer = 0 To numberOfBrowsers - 1
Debug.WriteLine("Start adding browsers")
Browsers(counter) = New WebControl
With Browsers(counter)
Debug.WriteLine("Setting properties")
.Dock = DockStyle.Fill
.Name = "Browers" & counter
.Source = New Uri(UrlList(counter))
If counter = 0 Then
.Visible = True
Else
.Visible = False
End If
End With
'Add the actual browsers after the properties have been set
Me.Controls.Add(Browsers(counter))
AddHandler Browsers(counter).LoadingFrameComplete, AddressOf All_Browsers_Loaded
Debug.WriteLine("Browsers is added. Current Count is: " & counter)
Next
Catch ex As Exception
Debug.WriteLine(ex)
End Try
'Count all the added browsers to alternate between them
Dim allWebBrowser As New List(Of Control)
For Each web As WebControl In FindControlRecursive(allWebBrowser, Me, GetType(WebControl))
Debug.WriteLine("Webcontrols on form: " & web.Name)
BrowserCount = +1
Next
'Start timer to switch browsers
Timer1.Interval = 1000
Timer1.Start()
End Sub
Private Sub All_Browsers_Loaded(ByVal sender As System.Object, ByVal e As Awesomium.Core.FrameEventArgs)
Dim Browser As WebControl = DirectCast(sender, WebControl)
Browser.Zoom = "80"
Debug.WriteLine("Browsers is now zoomed out?")
End Sub
Public Function ChangeBrowser()
Dim Changed As Boolean
For I As Integer = 0 To BrowserCount
With Browsers(I)
If Browsers(I).Visible = True Then
Browsers(I).Visible = False
Changed = True
End If
If Changed = True Then
Browsers(I).Visible = True
Changed = False
End If
If I = BrowserCount Then
Browsers(0).Visible = True
Continue For
End If
End With
Next
Return False
End Function
In the ChangeBrowser() function I'm trying to get the first visible browser and make it not visible. Then set the Changed Boolean to true.
Whats the best way to handle this?

Print multiple pages

I'm converting from VB5 and am trying to get the equivalent of printer.NewPage in VB.NET.
My code is given below, but it simply prints the two lines on a single page.
The program prints two pages of calculated results (arrays etc), it is not reading and printing a file.
How do I get a second page?
Private Sub PrintGeneralReport()
Dim PrintPreviewSelected As Boolean = True
'Set the doc to print
Dim pDoc As New PrintDocument
pDoc.PrintController = New StandardPrintController 'turns off the printing page x of y dialog
'Get the printer to use
If Me.PrintDialog1.ShowDialog() = DialogResult.OK Then
pDoc.PrinterSettings.PrinterName = Me.PrintDialog1.PrinterSettings.PrinterName
'pDoc.DefaultPageSettings.Margins = New Margins(75, 50, 50, 50)
pDoc.DefaultPageSettings.Margins = New Margins(40, 10, 10, 10)
pDoc.OriginAtMargins = True
Else
pDoc = Nothing
Exit Sub
End If
' Install the PrintPage event handler.
AddHandler pDoc.PrintPage, AddressOf PrintGenReport
If PrintPreviewSelected Then
''print preview
PrintPreviewDialog1.Document = pDoc
PrintPreviewDialog1.UseAntiAlias = True
PrintPreviewDialog1.WindowState = FormWindowState.Maximized
PrintPreviewDialog1.ShowDialog()
Else
'just print
pDoc.Print()
End If
RemoveHandler pDoc.PrintPage, AddressOf PrintGenReport
End Sub
Private Sub PrintGenReport(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs)
Dim fnt10 As Font = New Font("Courier New", 10, FontStyle.Regular)
e.Graphics.DrawString("Page 1", fnt10, Brushes.Black, 20, 100)
'ROARK1.Print_GeneralReportRK(Me, e)
e.HasMorePages = True
e.Graphics.DrawString("Page 2", fnt10, Brushes.Black, 20, 200)
'ROARK1.Print_MemberActions(e)
e.HasMorePages = False
End Sub
Try this:
Private PageNum As Integer = 1
Private Sub PrintGenReport(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs)
Dim fnt10 As Font = New Font("Courier New", 10, FontStyle.Regular)
e.Graphics.DrawString("Page " & PageNum.ToString(), fnt10, Brushes.Black, 20, 100 * PageNum)
e.HasMorePages = (PageNum < 2)
PageNum += 1
End Sub
Note the PageNum variable is defined at the class level. You should also add a line to the PrintGeneralReport() method to set it back to 1 at the beginning of each print job.