Why does my for loop not work? - vb.net

I am trying to run a small test to see if the value sent matches the value received. however, in most cases the value received seems to be one step behind!
For i As Decimal = 0 To 127
j = Hex(i)
stsResult = PCANBasic.Read(m_PcanHandle, myCANMsg, CANTimeStamp)
CANMsg = New TPCANMsg()
CANMsg.DATA = CType(Array.CreateInstance(GetType(Byte), 8), Byte())
CANMsg.ID = Convert.ToInt32(240, 16)
CANMsg.LEN = Convert.ToByte(8)
CANMsg.MSGTYPE = TPCANMessageType.PCAN_MESSAGE_STANDARD
CANMsg.DATA(3) = Convert.ToByte(10, 16)
CANMsg.DATA(4) = Convert.ToByte(j, 16)
CANMsg.DATA(5) = Convert.ToByte(99, 16)
PCANBasic.Write(m_PcanHandle, CANMsg)
ReadAnalogVal() ' Sents a request message so that the it updates the message about to be read
stsResult = PCANBasic.Read(m_PcanHandle, myCANMsg, CANTimeStamp) 'reads bus and populates var myCANMsg with the data
hiBit = Hex(myCANMsg.DATA(0))
If (stsResult <> TPCANStatus.PCAN_ERROR_QRCVEMPTY) Then
If myCANMsg.ID = 960 And hiBit = j Then
MessageBox.Show("you sent: " & j & " and Recieved: " & hiBit)
Else
MessageBox.Show("Response did NOT match output. Output:" & j & " Recieved: " & hiBit)
End If
End If
Next
CANMsg = New TPCANMsg()
CANMsg.DATA = CType(Array.CreateInstance(GetType(Byte), 8), Byte())
CANMsg.ID = Convert.ToInt32(240, 16)
CANMsg.LEN = Convert.ToByte(8)
CANMsg.MSGTYPE = TPCANMessageType.PCAN_MESSAGE_STANDARD
CANMsg.DATA(3) = Convert.ToByte(0, 16)
CANMsg.DATA(4) = Convert.ToByte(0, 16)
PCANBasic.Write(m_PcanHandle, CANMsg)
iBuffer = PCANBasic.PCAN_FILTER_OPEN
result = PCANBasic.SetValue(PCANBasic.PCAN_USBBUS1, TPCANParameter.PCAN_MESSAGE_FILTER, iBuffer, Convert.ToUInt32(Len(iBuffer)))
If result <> TPCANStatus.PCAN_ERROR_OK Then
' An error occurred, get a text describing the error and show it
'
PCANBasic.GetErrorText(result, 0, strMsg)
MessageBox.Show(strMsg.ToString)
Else
MessageBox.Show("Filter is open again")
End If
End Function
This seems to work for some cases and then most of the time it does not match, any advise would be appreciated. this is my first VB.NET application so i may be making an amateur mistake. I have looked into Multi-threading but I'm not entirely sure how to make it work in this case.
Here is more of the application:
Imports System.Text
' Inclusion of PEAK PCAN-Basic namespace
'
Imports System.Text
Inclusion of PEAK PCAN-Basic namespace
Imports Peak.Can.Basic
Imports TPCANHandle = System.UInt16
Imports TPCANBitrateFD = System.String
Imports TPCANTimestampFD = System.UInt64
Public Class Form1
Public Sub New()
' Initializes Form's component
'
InitializeComponent()
' Initializes specific components
'
InitializeBasicComponents()
End Sub
''' <summary>
''' Message Status structure used to show CAN Messages
''' in a ListView
''' </summary>
Private Class MessageStatus
Private m_Msg As TPCANMsgFD
Private m_TimeStamp As TPCANTimestampFD
Private m_oldTimeStamp As TPCANTimestampFD
Private m_iIndex As Integer
Private m_Count As Integer
Private m_bShowPeriod As Boolean
Private m_bWasChanged As Boolean
Public Sub New(ByVal canMsg As TPCANMsgFD, ByVal canTimestamp As TPCANTimestampFD, ByVal listIndex As Integer)
m_Msg = canMsg
m_TimeStamp = canTimestamp
m_oldTimeStamp = canTimestamp
m_iIndex = listIndex
m_Count = 1
m_bShowPeriod = True
m_bWasChanged = False
End Sub
Public Sub Update(ByVal canMsg As TPCANMsgFD, ByVal canTimestamp As TPCANTimestampFD)
m_Msg = canMsg
m_oldTimeStamp = m_TimeStamp
m_TimeStamp = canTimestamp
m_bWasChanged = True
m_Count += 1
End Sub
Private Function GetMsgTypeString() As String
Dim strTemp As String
If (m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_STATUS) = TPCANMessageType.PCAN_MESSAGE_STATUS Then
Return "STATUS"
End If
If (m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_ERRFRAME) = TPCANMessageType.PCAN_MESSAGE_ERRFRAME Then
Return "ERROR"
End If
If (m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_EXTENDED) = TPCANMessageType.PCAN_MESSAGE_EXTENDED Then
strTemp = "EXT"
Else
strTemp = "STD"
End If
If (m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_RTR) = TPCANMessageType.PCAN_MESSAGE_RTR Then
strTemp += "/RTR"
Else
If (m_Msg.MSGTYPE > TPCANMessageType.PCAN_MESSAGE_EXTENDED) Then
strTemp += " [ "
If ((m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_FD) = TPCANMessageType.PCAN_MESSAGE_FD) Then
strTemp += " FD"
End If
If ((m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_BRS) = TPCANMessageType.PCAN_MESSAGE_BRS) Then
strTemp += " BRS"
End If
If ((m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_ESI) = TPCANMessageType.PCAN_MESSAGE_ESI) Then
strTemp += " ESI"
End If
strTemp += " ]"
End If
End If
Return strTemp
End Function
Private Function GetIdString() As String
If (m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_EXTENDED) = TPCANMessageType.PCAN_MESSAGE_EXTENDED Then
Return String.Format("{0:X8}h", m_Msg.ID)
Else
Return String.Format("{0:X3}h", m_Msg.ID)
End If
End Function
Private Function GetDataString() As String
Dim strTemp As String
strTemp = ""
If (m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_RTR) = TPCANMessageType.PCAN_MESSAGE_RTR Then
strTemp = "Remote Request"
Else
For i As Integer = 0 To Form1.GetLengthFromDLC(m_Msg.DLC, (m_Msg.MSGTYPE And TPCANMessageType.PCAN_MESSAGE_FD) = 0) - 1
strTemp += String.Format("{0:X2} ", m_Msg.DATA(i))
Next
End If
Return strTemp
End Function
Private Function GetTimeString() As String
Dim fTime As Double
fTime = (m_TimeStamp / 1000.0R)
If m_bShowPeriod Then
fTime -= (m_oldTimeStamp / 1000.0R)
End If
Return fTime.ToString("F1")
End Function
Public ReadOnly Property CANMsg() As TPCANMsgFD
Get
Return m_Msg
End Get
End Property
Public ReadOnly Property Timestamp() As TPCANTimestampFD
Get
Return m_TimeStamp
End Get
End Property
Public ReadOnly Property Position() As Integer
Get
Return m_iIndex
End Get
End Property
Public ReadOnly Property TypeString() As String
Get
Return GetMsgTypeString()
End Get
End Property
Public ReadOnly Property IdString() As String
Get
Return GetIdString()
End Get
End Property
Public ReadOnly Property DataString() As String
Get
Return GetDataString()
End Get
End Property
Public ReadOnly Property Count() As Integer
Get
Return m_Count
End Get
End Property
Public Property ShowingPeriod() As Boolean
Get
Return m_bShowPeriod
End Get
Set(ByVal value As Boolean)
If m_bShowPeriod Xor value Then
m_bShowPeriod = value
m_bWasChanged = True
End If
End Set
End Property
Public Property MarkedAsUpdated() As Boolean
Get
Return m_bWasChanged
End Get
Set(ByVal value As Boolean)
m_bWasChanged = value
End Set
End Property
Public ReadOnly Property TimeString() As String
Get
Return GetTimeString()
End Get
End Property
End Class
''' <summary>
''' Read-Delegate Handler
''' </summary>
Private Delegate Sub ReadDelegateHandler()
''' <summary>
''' Saves the desired connection mode
''' </summary>
Private m_IsFD As Boolean
''' <summary>
''' Saves the handle of a PCAN hardware
''' </summary>
Private m_PcanHandle As TPCANHandle
''' <summary>
''' Saves the baudrate register for a conenction
''' </summary>
Private m_Baudrate As TPCANBaudrate
''' <summary>
''' Saves the type of a non-plug-and-play hardware
''' </summary>
Private m_HwType As TPCANType
''' <summary>
''' Stores the status of received messages for its display
''' </summary>
Private m_LastMsgsList As System.Collections.ArrayList
''' <summary>
''' Read Delegate for calling the function "ReadMessages"
''' </summary>
Private m_ReadDelegate As ReadDelegateHandler
''' <summary>
''' Receive-Event
''' </summary>
Private m_ReceiveEvent As System.Threading.AutoResetEvent
''' <summary>
''' Thread for message reading (using events)
''' </summary>
Private m_ReadThread As System.Threading.Thread
''' <summary>
''' Handles of the current available PCAN-Hardware
''' </summary>
Private m_HandlesArray As TPCANHandle()

Related

Print Text or HTML to PDF without changing default printer and using Microsoft Print To PDF and no user prompts

I have a need to PDF print the body of an email, text or html, without human intervention and without changing the default printer.
I have answered my own question using pieces from StackOverflow and Microsoft. The answer is not perfect but it does work for me. Part of this sharing is to get some feedback on a better way to do this and provide an answer (maybe not the best one) to someone else problem.
'Usage
'Dim printpdf As New PrintToPDF
'printpdf.HTMLToPDF(filecontents, PDFfilename)
'or
'printpdf.TextToPDF(filecontents, PDFfilename)
Imports System.Drawing 'if not used in a form
Imports System.Windows.Forms 'if not used in a form
Imports System.Drawing.Drawing2D
Imports System.Drawing.Printing
Public Class PrintToPDF
Public Property PDFPrinterName As String = "Microsoft Print to PDF"
Public Property TextPrintFont As Font = New Font("Arial", 10, FontStyle.Regular)
Public Property SaveImagesOfPages As Boolean = False
Public Property SaveImagesOfPagesPath As String = "c:\temp"
Public Property SaveImagePageName As String = "testemail"
''' <summary>
''' Get or Set the color of the margin. The padded space around the image of the captured HTML
''' </summary>
''' <returns></returns>
Public Property ImageBorderColor As Color = Color.White
Private _PDFMargin As Margins = New Margins(20, 20, 20, 20)
''' <summary>
''' Get or Set printer margin spacing
''' </summary>
''' <returns></returns>
Public Property PDFMargin As Margins
Get
Return _PDFMargin
End Get
Set(value As Margins)
_PDFMargin = value
End Set
End Property
Private _PixelMargin As Integer = 5
''' <summary>
''' Get or Set the margin (ALL) added to the document to provide clean print edges for converting HTML or RTF.
''' Must be a positive integer
''' </summary>
''' <returns></returns>
Public Property PixelMargin As Integer
Get
Return _PixelMargin
End Get
Set(value As Integer)
If value < 1 Then value = 1
_PixelMargin = value
_PaperHeight = PDFPaperSize.Height - (2 * PixelMargin) 'x2 for L/R and T/B
_PaperWidth = PDFPaperSize.Width - (2 * PixelMargin) 'x2 for L/R and T/B
End Set
End Property
Private _PDFPaperSize As PaperSize = New PaperSize("Letter", 850, 1100)
Public Property PDFPaperSize As PaperSize
Get
Return _PDFPaperSize
End Get
Set(value As PaperSize)
_PDFPaperSize = value
_PaperHeight = PDFPaperSize.Height - (2 * PixelMargin) 'x2 for L/R and T/B
_PaperWidth = PDFPaperSize.Width - (2 * PixelMargin) 'x2 for L/R and T/B
End Set
End Property
'A polling variable to determine when the print job has completed
Private _PrintingComplete As Boolean = False
Private _PrintPDF As PrintDocument
Private _webControl As WebBrowser
Private _WEBControl_BMP As Bitmap = Nothing
Private _BMP_YOffset As Integer = 0 ' The variable that moves the bmp page/image down to the next segment/page
Private _BMP_PageCount As Integer = 1
Private _BMP_RemainingHeight As Integer = 0
Private _rftControl As RichTextBox
Private _RTFControl_BMP As Bitmap = Nothing
Private _TXT_PageCount As Integer = 1
Private _TextToPrint As String = ""
'just less than the 1100 for a letter so that it doesnt cut off so harse at the edge of a page
Private _PaperHeight As Integer = 1100
Private _PaperWidth As Integer = 850
Public Sub New()
End Sub
''' <summary>
''' For development. Does not work for TextToPDF
''' </summary>
''' <param name="SavePages"></param>
''' <param name="SavePagesPath"></param>
''' <param name="SavePageName"></param>
Public Sub New(ByVal SavePages As Boolean, ByVal SavePagesPath As String, ByVal SavePageName As String)
_SaveImagesOfPages = SavePages
_SaveImagesOfPagesPath = SavePagesPath
_SaveImagePageName = SavePageName
End Sub
#Region "HTML"
''' <summary>
''' Prints an image of rendered HTML to PDF
''' </summary>
''' <param name="HTMLCode"></param>
''' <param name="SaveToPDFFile"></param>
''' <returns></returns>
Public Function HTMLToPDF(ByVal HTMLCode As String, ByVal SaveToPDFFile As String) As Boolean
Dim rtnBool As Boolean = False
'Dim printPDF As New PrintDocument
Try
_PrintingComplete = False
If (SaveImagesOfPagesPath <> "") AndAlso (Not SaveImagesOfPagesPath.EndsWith("\")) Then SaveImagesOfPagesPath += "\"
_webControl = New WebBrowser 'give me a new instance for this event
_PrintPDF = New PrintDocument
With _PrintPDF
.DocumentName = "docHTMLCode" 'give it something for a name, you can see this in the print spooler as the job runs
.PrintController = New Printing.StandardPrintController
.DefaultPageSettings.Landscape = False
.DefaultPageSettings.PaperSize = PDFPaperSize 'New PaperSize("Letter", 850, 1100) '.DefaultPageSettings.PrinterSettings.PaperSizes(PaperKind.Letter) 'New PaperSize("Legal", 850, 1400)
'_PaperHeight = .DefaultPageSettings.PaperSize.Height
'.DefaultPageSettings.PrinterResolution = .PrinterSettings.PrinterResolutions(1)
.DefaultPageSettings.Color = True
.DefaultPageSettings.Margins = PDFMargin 'not currently being followed, that's why the HTMLInjectMargin was created
.PrinterSettings.Copies = 1
.PrinterSettings.PrinterName = _PDFPrinterName '"Microsoft Print to PDF"
.PrinterSettings.PrintToFile = True
.PrinterSettings.PrintFileName = SaveToPDFFile
End With
Dim pageBottom As Integer = 1
With _webControl
.ClientSize = New Size(_PaperWidth, _PaperHeight) 'give it some place to start
.DocumentText = "0"
.Document.OpenNew(True)
.Document.Write(HTMLCode)
.Refresh() 'let the new html load
While .ReadyState <> WebBrowserReadyState.Complete
Application.DoEvents()
End While
'make the size the same as an even number of full sheets of paper
pageBottom = .Document.Body.ScrollRectangle.Height - (_PixelMargin * 2) 'this is the length of the page as it was given
'now make the page long enough to be a full sheet of paper
If (pageBottom <= _PaperHeight) Then
'1 page and short
pageBottom = _PaperHeight
Else
'multiple pages
pageBottom = (((pageBottom \ _PaperHeight) + 1) * _PaperHeight)
End If
'changes the viewable size of the control
.ClientSize = New Size(_PaperWidth, pageBottom) 'now the client size is the same as X full sheets of paper
.Refresh() 'redraw so we can get a proper image capture, just in case
End With
'with everything set, do the print
AddHandler _PrintPDF.PrintPage, AddressOf WebControlPrintPage
AddHandler _PrintPDF.EndPrint, AddressOf WebControlEndPrint
_BMP_PageCount = 1 'give it a start page
'set some bounds for the big picture
_WEBControl_BMP = New Bitmap(_webControl.Bounds.Width - SystemInformation.VerticalScrollBarWidth, _webControl.Bounds.Height) '_webControl.Document.Body.ScrollRectangle.Bottom)
_webControl.DrawToBitmap(_WEBControl_BMP, _webControl.Bounds) 'fill those bounds with an image
_BMP_RemainingHeight = _WEBControl_BMP.Height 'after this, this height will start being subtracted
'Debug.Print("_webControl.Bounds.Width : " & _webControl.Bounds.Width.ToString & " _webControl.Bounds.Height : " & _webControl.Bounds.Height.ToString)
If SaveImagesOfPages Then Image.FromHbitmap(_WEBControl_BMP.GetHbitmap).Save(SaveImagesOfPagesPath & "FullPage_" & _SaveImagePageName & ".png", Imaging.ImageFormat.Png)
_PrintPDF.Print() 'this creates the actual pdf file from the PrintPage/WebControlPrint event
rtnBool = True
Stall(1) 'buy some time. noticed that even at this point, after the print, the calling function is unable to access the pdf just created as it is "busy"
'clean up
_webControl.Dispose()
_PrintPDF.Dispose()
_WEBControl_BMP.Dispose()
Catch ex As Exception
Debug.Print(ex.ToString)
End Try
Return rtnBool
End Function
Private Sub WebControlEndPrint(ByVal sender As Object, ByVal e As PrintEventArgs) 'Handles _PrintPDF.EndPrint
_PrintingComplete = True
'Stall(1)
End Sub
Private Sub WebControlPrintPage(ByVal sender As Object, ByVal e As PrintPageEventArgs) 'Handles _PrintPDF.PrintPage
'Dim rtnBool As Boolean = False
Try
'e.Graphics.PageUnit = GraphicsUnit.Pixel 'make the print super small and unreadable
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality
e.Graphics.CompositingQuality = Drawing2D.CompositingQuality.HighQuality
e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
'Dim destRect As RectangleF
Dim endOfPage As Integer = 0
Dim HasMorePages As Boolean = False
endOfPage = (_PaperHeight * _BMP_PageCount)
'Debug.Print("0, " & _BMP_YOffset.ToString & ", " & _WEBControl_BMP.Width.ToString & ", " & (endOfPage - _BMP_YOffset).ToString)
If (_BMP_RemainingHeight > _PaperHeight) Then 'more pages to print
'multipage
HasMorePages = True
Else
HasMorePages = False
End If
Dim srcRect As RectangleF = New RectangleF(0, _BMP_YOffset, _WEBControl_BMP.Width, (endOfPage - _BMP_YOffset)) 'region that should represent the location on the pdf to place the image
Dim b As Bitmap = _WEBControl_BMP.Clone(srcRect, _WEBControl_BMP.PixelFormat) 'the segment to print
Dim img As Image = AppendBorder(Image.FromHbitmap(b.GetHbitmap), PixelMargin)
If SaveImagesOfPages Then img.Save(SaveImagesOfPagesPath & _SaveImagePageName & "_Page_" & _BMP_PageCount.ToString & ".png", Imaging.ImageFormat.Png)
e.Graphics.DrawImage(img, e.MarginBounds)
_BMP_YOffset += _PaperHeight 'hold this value for the next run
_BMP_PageCount += 1
_BMP_RemainingHeight -= _PaperHeight 'remove a page worth of information
e.HasMorePages = HasMorePages
Catch ex As Exception
Debug.Print(ex.ToString)
End Try
'on exit clears the print spooler queue
End Sub
''' <summary>
''' Extracts text from HTML code
''' </summary>
''' <param name="HTMLCode"></param>
''' <returns></returns>
Public Function HtmlToPlainText(ByVal HTMLCode As String) As String
Dim rtnText As String = ""
Try
Dim webControl As New WebBrowser
webControl.DocumentText = "0"
webControl.Document.OpenNew(True)
webControl.Document.Write(HTMLCode)
webControl.Refresh()
'ExecCommand is supposed to be being deprecated soon, will have to come up with something different soon
webControl.Document.ExecCommand("SelectAll", False, Nothing)
webControl.Document.ExecCommand("Copy", False, Nothing)
webControl.Dispose()
webControl = Nothing
rtnText = Clipboard.GetText
Catch ex As Exception
Debug.Print(ex.ToString)
End Try
Return rtnText
End Function
#End Region
#Region "TEXT"
''' <summary>
''' Prints the text to a PDF file
''' </summary>
''' <param name="TextToPrint"></param>
''' <param name="SaveToPDFFile"></param>
''' <returns></returns>
Public Function TextToPDF(ByVal TextToPrint As String, ByVal SaveToPDFFile As String) As Boolean
Dim rtnBool As Boolean = False
Try
_PrintingComplete = False
_TextToPrint = TextToPrint
_PrintPDF = New PrintDocument
With _PrintPDF
.DocumentName = "docText" 'name shown in the print spooler
.PrintController = New Printing.StandardPrintController
.DefaultPageSettings.Landscape = False
.DefaultPageSettings.PaperSize = PDFPaperSize
.DefaultPageSettings.Color = True
.DefaultPageSettings.Margins = PDFMargin
.PrinterSettings.Copies = 1
.PrinterSettings.PrinterName = _PDFPrinterName
.PrinterSettings.PrintToFile = True
.PrinterSettings.PrintFileName = SaveToPDFFile
End With
'with everything set, do the print
AddHandler _PrintPDF.PrintPage, AddressOf TextPrintPage
AddHandler _PrintPDF.EndPrint, AddressOf TextEndPrint
_TXT_PageCount = 1 'give it a start page
_PrintPDF.Print() 'this creates the actual pdf file from the PrintPage/WebControlPrint event
rtnBool = True
Stall(1) 'buy some time. noticed that even at this point, after the print, the calling function is unable to access the pdf just created as it is "busy"
'clean up
_PrintPDF.Dispose()
Catch ex As Exception
Debug.Print(ex.ToString)
End Try
Return rtnBool
End Function
Private Sub TextPrintPage(ByVal sender As Object, ByVal e As PrintPageEventArgs)
'_TextToPrint
Dim charactersOnPage As Integer = 0
Dim linesPerPage As Integer = 0
e.Graphics.MeasureString(_TextToPrint, TextPrintFont, e.MarginBounds.Size, StringFormat.GenericTypographic, charactersOnPage, linesPerPage)
e.Graphics.DrawString(_TextToPrint, TextPrintFont, Brushes.Black, e.MarginBounds, StringFormat.GenericTypographic)
_TextToPrint = _TextToPrint.Substring(charactersOnPage)
e.HasMorePages = (_TextToPrint.Length > 0)
End Sub
Private Sub TextEndPrint(ByVal sender As Object, ByVal e As PrintEventArgs)
_PrintingComplete = True
End Sub
''' <summary>
''' Opens a text file and prints its contents to PDF
''' </summary>
''' <param name="FullPathDocumentToPrint"></param>
''' <param name="SaveToPDFFile"></param>
''' <returns></returns>
Public Function TextDocumentToPDF(ByVal FullPathDocumentToPrint As String, ByVal SaveToPDFFile As String) As Boolean ', Optional ByVal msWaitTime As Integer = 10000
Dim rtnBoolean As Boolean = False
If (FullPathDocumentToPrint <> "") Then
Try
_TextToPrint = My.Computer.FileSystem.ReadAllText(FullPathDocumentToPrint)
rtnBoolean = TextToPDF(_TextToPrint, SaveToPDFFile)
Catch ex As Exception
rtnBoolean = False
Debug.Print(ex.ToString)
End Try
End If
Return rtnBoolean
End Function
#End Region
Private Function AppendBorder(ByVal original As Image, ByVal borderWidth As Integer) As Image
Dim borderColor As Color = ImageBorderColor 'Color.Red
Dim mypen As New Pen(borderColor, borderWidth * 2)
Dim newSize As Size = New Size(original.Width + borderWidth * 2, original.Height + borderWidth * 2)
Dim img As Bitmap = New Bitmap(newSize.Width, newSize.Height)
Dim g As Graphics = Graphics.FromImage(img)
'g.Clear(borderColor)
g.DrawImage(original, New Point(borderWidth, borderWidth))
g.DrawRectangle(mypen, 0, 0, newSize.Width, newSize.Height)
g.Dispose()
Return img
End Function
''' <summary>
''' Creates a loop for a given number of seconds
''' </summary>
''' <param name="seconds"></param>
''' <remarks></remarks>
Public Sub Stall(ByVal Seconds As Single)
'Debug.Print(Now.ToString)
Dim eDate As Date = Date.Now.AddSeconds(Seconds)
While Now < eDate
Application.DoEvents()
End While
'Debug.Print(Now.ToString)
End Sub
End Class

How to read data from serial port in vb.net?

I made a class and there is this sub named SendUSSD, when this is called it sends a ussd code like *123# to a COM port where a gsm mobile is connected. This ussd is supposed to return the mobile balance.
If IsOpen = True Then 'checks if the port is open
SMSPort.WriteLine("AT+CUSD=1,""*123#""" vbCr) 'this sends the ussd code
Form1.TextBox2.Text = SMSPort.ReadLine().ToString() 'this shows the response
End If
Now the problem is sometimes I get the full response like "Your current balance is so and so". But, most of the time I get a part of the message like "Your curr". My guess is that it takes some time to get the response, so how do I make this Form1.TextBox2.Text = SMSPort.ReadLine().ToString() line wait until the last character which is a full-stop to appear and then execute the line?
im using this class to connect com ports.
'connect like this
Public comm As New CommunicationManager
comm.Parity = "None"
comm.StopBits = "One"
comm.DataBits = "8"
comm.BaudRate = "38400"
comm.PortName = comport_ismi
comm.OpenPort()
and the class
Imports System.Text
Imports System.Drawing
Imports System.IO.Ports
Imports System.Windows.Forms
Public Class CommunicationManager
#Region "Manager Enums"
''' <summary>
''' enumeration to hold our transmission types
''' </summary>
Public Enum TransmissionType
Text
Hex
End Enum
''' <summary>
''' enumeration to hold our message types
''' </summary>
Public Enum MessageType
Incoming
Outgoing
Normal
Warning
[Error]
End Enum
#End Region
#Region "Manager Variables"
'property variables
Private _baudRate As String = String.Empty
Private _parity As String = String.Empty
Private _stopBits As String = String.Empty
Private _dataBits As String = String.Empty
Private _portName As String = String.Empty
Private _transType As TransmissionType
Private _displayWindow As RichTextBox
'global manager variables
Private MessageColor As Color() = {Color.Blue, Color.Green, Color.Black, Color.Orange, Color.Red}
Private comPort As New SerialPort()
#End Region
#Region "Manager Properties"
''' <summary>
''' Property to hold the BaudRate
''' of our manager class
''' </summary>
Public Property BaudRate() As String
Get
Return _baudRate
End Get
Set(value As String)
_baudRate = value
End Set
End Property
''' <summary>
''' property to hold the Parity
''' of our manager class
''' </summary>
Public Property Parity() As String
Get
Return _parity
End Get
Set(value As String)
_parity = value
End Set
End Property
''' <summary>
''' property to hold the StopBits
''' of our manager class
''' </summary>
Public Property StopBits() As String
Get
Return _stopBits
End Get
Set(value As String)
_stopBits = value
End Set
End Property
''' <summary>
''' property to hold the DataBits
''' of our manager class
''' </summary>
Public Property DataBits() As String
Get
Return _dataBits
End Get
Set(value As String)
_dataBits = value
End Set
End Property
''' <summary>
''' property to hold the PortName
''' of our manager class
''' </summary>
Public Property PortName() As String
Get
Return _portName
End Get
Set(value As String)
_portName = value
End Set
End Property
''' <summary>
''' property to hold our TransmissionType
''' of our manager class
''' </summary>
Public Property CurrentTransmissionType() As TransmissionType
Get
Return _transType
End Get
Set(value As TransmissionType)
_transType = value
End Set
End Property
''' <summary>
''' property to hold our display window
''' value
''' </summary>
Public Property DisplayWindow() As RichTextBox
Get
Return _displayWindow
End Get
Set(value As RichTextBox)
_displayWindow = value
End Set
End Property
#End Region
#Region "Manager Constructors"
''' <summary>
''' Constructor to set the properties of our Manager Class
''' </summary>
''' <param name="baud">Desired BaudRate</param>
''' <param name="par">Desired Parity</param>
''' <param name="sBits">Desired StopBits</param>
''' <param name="dBits">Desired DataBits</param>
''' <param name="name">Desired PortName</param>
Public Sub New(baud As String, par As String, sBits As String, dBits As String, name As String, rtb As RichTextBox)
_baudRate = baud
_parity = par
_stopBits = sBits
_dataBits = dBits
_portName = name
_displayWindow = rtb
'now add an event handler
AddHandler comPort.DataReceived, New SerialDataReceivedEventHandler(AddressOf comPort_DataReceived)
End Sub
''' <summary>
''' Comstructor to set the properties of our
''' serial port communicator to nothing
''' </summary>
Public Sub New()
_baudRate = String.Empty
_parity = String.Empty
_stopBits = String.Empty
_dataBits = String.Empty
_portName = comport_ismi
_displayWindow = Nothing
'add event handler
AddHandler comPort.DataReceived, New SerialDataReceivedEventHandler(AddressOf comPort_DataReceived)
End Sub
#End Region
#Region "WriteData"
Public Sub WriteData(msg As String)
Select Case CurrentTransmissionType
Case TransmissionType.Text
'first make sure the port is open
'if its not open then open it
If Not (comPort.IsOpen = True) Then
comPort.Open()
End If
'send the message to the port
comPort.Write(msg)
'display the message
DisplayData(MessageType.Outgoing, msg & Convert.ToString(vbLf))
Exit Select
Case TransmissionType.Hex
Try
'convert the message to byte array
Dim newMsg As Byte() = HexToByte(msg)
'send the message to the port
comPort.Write(newMsg, 0, newMsg.Length)
'convert back to hex and display
DisplayData(MessageType.Outgoing, ByteToHex(newMsg) & Convert.ToString(vbLf))
Catch ex As FormatException
'display error message
DisplayData(MessageType.[Error], ex.Message)
Finally
_displayWindow.SelectAll()
End Try
Exit Select
Case Else
'first make sure the port is open
'if its not open then open it
If Not (comPort.IsOpen = True) Then
comPort.Open()
End If
'send the message to the port
comPort.Write(msg)
'display the message
DisplayData(MessageType.Outgoing, msg & Convert.ToString(vbLf))
Exit Select
End Select
End Sub
#End Region
#Region "HexToByte"
''' <summary>
''' method to convert hex string into a byte array
''' </summary>
''' <param name="msg">string to convert</param>
''' <returns>a byte array</returns>
Private Function HexToByte(msg As String) As Byte()
'remove any spaces from the string
msg = msg.Replace(" ", "")
'create a byte array the length of the
'divided by 2 (Hex is 2 characters in length)
Dim comBuffer As Byte() = New Byte(msg.Length / 2 - 1) {}
'loop through the length of the provided string
For i As Integer = 0 To msg.Length - 1 Step 2
'convert each set of 2 characters to a byte
'and add to the array
comBuffer(i / 2) = CByte(Convert.ToByte(msg.Substring(i, 2), 16))
Next
'return the array
Return comBuffer
End Function
#End Region
#Region "ByteToHex"
''' <summary>
''' method to convert a byte array into a hex string
''' </summary>
''' <param name="comByte">byte array to convert</param>
''' <returns>a hex string</returns>
Private Function ByteToHex(comByte As Byte()) As String
'create a new StringBuilder object
Dim builder As New StringBuilder(comByte.Length * 3)
'loop through each byte in the array
For Each data As Byte In comByte
'convert the byte to a string and add to the stringbuilder
builder.Append(Convert.ToString(data, 16).PadLeft(2, "0"c).PadRight(3, " "c))
Next
'return the converted value
Return builder.ToString().ToUpper()
End Function
#End Region
#Region "DisplayData"
''' <summary>
''' method to display the data to & from the port
''' on the screen
''' </summary>
''' <param name="type">MessageType of the message</param>
''' <param name="msg">Message to display</param>
<STAThread> _
Private Sub DisplayData(type As MessageType, msg As String)
'_displayWindow.Invoke(New EventHandler(Sub()
' _displayWindow.SelectedText = String.Empty
' _displayWindow.SelectionFont = New Font(_displayWindow.SelectionFont, FontStyle.Bold)
' _displayWindow.SelectionColor = MessageColor(CInt(type))
' _displayWindow.AppendText(msg)
' _displayWindow.ScrollToCaret()
' End Sub))
End Sub
#End Region
#Region "OpenPort"
Public Function OpenPort() As Boolean
Try
'first check if the port is already open
'if its open then close it
If comPort.IsOpen = True Then
comPort.Close()
End If
'set the properties of our SerialPort Object
comPort.BaudRate = Integer.Parse(_baudRate)
'BaudRate
comPort.DataBits = Integer.Parse(_dataBits)
'DataBits
comPort.StopBits = DirectCast([Enum].Parse(GetType(StopBits), _stopBits), StopBits)
'StopBits
comPort.Parity = DirectCast([Enum].Parse(GetType(Parity), _parity), Parity)
'Parity
comPort.PortName = _portName
'PortName
'now open the port
comPort.Open()
'display message
DisplayData(MessageType.Normal, "Port AÇILDI: " + DateTime.Now + vbLf)
'return true
Return True
Catch ex As Exception
DisplayData(MessageType.[Error], ex.Message)
Return False
End Try
End Function
#End Region
#Region "ClosePort"
Public Function ClosePort() As Boolean
Try
'first check if the port is already open
'if its open then close it
If comPort.IsOpen = True Then
comPort.Close()
End If
'display message
DisplayData(MessageType.Normal, "Port KAPANDI: " + DateTime.Now + vbLf)
'return true if port is closed
If comPort.IsOpen = False Then
Return True
End If
DisplayData(MessageType.Normal, "Kapatmada hata oluştu" & vbLf)
Return False
Catch ex As Exception
DisplayData(MessageType.[Error], ex.Message)
Return False
End Try
End Function
#End Region
#Region "SetParityValues"
Public Sub SetParityValues(obj As Object)
For Each str As String In [Enum].GetNames(GetType(Parity))
DirectCast(obj, ComboBox).Items.Add(str)
Next
End Sub
#End Region
#Region "SetStopBitValues"
Public Sub SetStopBitValues(obj As Object)
For Each str As String In [Enum].GetNames(GetType(StopBits))
DirectCast(obj, ComboBox).Items.Add(str)
Next
End Sub
#End Region
#Region "SetPortNameValues"
Public Sub SetPortNameValues(obj As Object)
For Each str As String In SerialPort.GetPortNames()
DirectCast(obj, ComboBox).Items.Add(str)
Next
End Sub
#End Region
#Region "comPort_DataReceived"
''' <summary>
''' method that will be called when theres data waiting in the buffer
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
Private Sub comPort_DataReceived(sender As Object, e As SerialDataReceivedEventArgs)
'determine the mode the user selected (binary/string)
Select Case CurrentTransmissionType
'user chose string
Case TransmissionType.Text
'read data waiting in the buffer
Dim msg As String = comPort.ReadExisting()
'display the data to the user
DisplayData(MessageType.Incoming, msg)
' + "\n"); **************
Exit Select
'user chose binary
Case TransmissionType.Hex
'retrieve number of bytes in the buffer
Dim bytes As Integer = comPort.BytesToRead
'create a byte array to hold the awaiting data
Dim comBuffer As Byte() = New Byte(bytes - 1) {}
'read the data and store it
comPort.Read(comBuffer, 0, bytes)
'display the data to the user
DisplayData(MessageType.Incoming, ByteToHex(comBuffer))
' + "\n");
Exit Select
Case Else
'read data waiting in the buffer
Dim str As String = comPort.ReadExisting()
'display the data to the user
DisplayData(MessageType.Incoming, str)
' + "\n");
Exit Select
End Select
End Sub
#End Region
End Class
I guess you are using the DataReceived event, if so, you can just take the data and split it by the lastIndexOf(Enviroment.NewLine).
you will have two part the first one is a string with some amount of lines and the second one is a string that contain no more lines.
You can take the first part and split it by new line and even create a new event (LineReceived).
for the second part(the part after the lastIndexOf(Enviroment.NewLine)) of the data just concatenate it to the beginning of the data that will arrive the next time.
Try setting comm.Newline. Probably should be vbCR.

Checking multiple checkboxes for numerc input vb.net / windows forms application

I have a form with 30 (currently) textboxes where a user will enter data. I need to restrict the user to numerical input only into each textbox, preferably before shifting focus to the next textbox.
Thanks to the internet I have found a piece of code that does this for an individual box. I want to avoid repeating this code 30 times if at all possible.
I see many answers referring to the error provider, but I'm not really clear on how to incorporate this into my code.
Could someone please take pity on me and show me an easy way of achieving my goal ? My head is spinning from all the posts I've read that nearly-but-not-quite answer my question.
Thankyou in anticipation
Steve
The following code restricts the input of a TextBox to numeric characters, arrow keys, back, clear and tab, as well as "-" and (exactly one) decimal point.
To avoid repeating the code 30 times, all you need to do is add another sub similar to Private Sub TextBox1_Enter(), where you replace all occurences of TextBox1 by the name of one of your TextBoxes until you have one such sub for each TextBox.
Public WithEvents NumericTextBox As MSForms.TextBox
Private Sub TextBox1_Enter()
Set NumericTextBox = TextBox1
End Sub
Private Sub NumericTextBox_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
Select Case KeyAscii
Case vbKey0 To vbKey9, vbKeyBack, vbKeyClear, vbKeyLeft, _
vbKeyRight, vbKeyUp, vbKeyDown, vbKeyTab
Case Asc("-")
If Instr(1, NumericTextBox.Text, "-") > 0 Or NumericTextBox.SelStart > 0 Then
KeyAscii = 0
End If
Case Asc(".")
If InStr(1, NumericTextBox.Text, ".") > 0 Then
KeyAscii = 0
End If
Case Else
KeyAscii = 0
End Select
End Sub
you can use below link
Accept only integer value
Public WithEvents textbox As MSForms.TextBox
Private Sub TextBox1_Enter()
Set NumericTextBox = TextBox1
End Sub
Private Sub textbox _KeyPress(ByVal e As System.Windows.Forms.KeyPressEventArgs
)
If (Microsoft.VisualBasic.Asc(e.KeyChar) < 48) _
Or (Microsoft.VisualBasic.Asc(e.KeyChar) > 57) Then
e.Handled = True
End If
If (Microsoft.VisualBasic.Asc(e.KeyChar) = 8) Then
e.Handled = False
End If
End Sub
Something I wrote today. Copy and paste it into a new class file, and be sure to import InputVerification where it's used.
Public Class InputVerification
Private ctrlArray As Control()
Private fltArray As String()
Private retMsg As String()
Public Property Case_Insensitive As Boolean
Public Const Yes As Boolean = True
Public Const No As Boolean = False
Public Sub New()
Case_Insensitive = True
End Sub
''' <summary>
''' Returns a value if InputFilter returns False.
''' </summary>
''' <value>Nothing.</value>
''' <returns>The offending control name and character, in a String array.</returns>
Public Property Return_Message As String()
Get
Return retMsg
End Get
Set(ByVal value As String())
retMsg = value
End Set
End Property
''' <summary>
''' The controls to be checked for valid input.
''' </summary>
''' <value>Any control type with a .Text property.</value>
''' <returns>An array with all the controls specified.</returns>
Public Property Controls() As Control()
Get
Return ctrlArray
End Get
Set(ByVal value As Control())
ctrlArray = value
End Set
End Property
''' <summary>
''' The characters to be allowed.
''' </summary>
''' <value>Any ASCII value.</value>
''' <returns>A String array for each control specified.</returns>
Public Property Filter() As String()
Get
Return fltArray
End Get
Set(ByVal value As String())
fltArray = value
End Set
End Property
''' <summary>
''' Checks to see if the characters entered match the valid characters.
''' Usage: {1, "a-d", 3, "0-5", "e-g", "?"}
''' The number defines how many filters for that control, in order.
''' </summary>
''' <returns>A boolean value.</returns>
''' <remarks>Use Return_Message, if this fails. First a number to define
''' the number of filters for that control. The next are as many filters
''' as you defined.</remarks>
Public Function InputFilter() As Boolean
Dim i As Integer = 0
Dim numFilters As Integer = 0
Dim oldPosition As Integer = 0
Dim newPosition As Integer = 0
Dim convValidChars As New Collection
For Each cntrl As Control In Controls
convValidChars.Clear()
oldPosition = newPosition
numFilters = Filter(newPosition)
newPosition = newPosition + numFilters
For k As Integer = oldPosition To newPosition
If Filter(k).ToString.Contains("-") And Filter(k).ToString.Length > 1 Then
Dim split() As String = Filter(k).ToString.Split("-"c)
Dim lowest, highest As Integer
If AscW(split(0).ToString) > AscW(split(1).ToString) Then
lowest = AscW(split(1))
highest = AscW(split(0))
Else
lowest = AscW(split(0))
highest = AscW(split(1))
End If
For j As Integer = lowest To highest
convValidChars.Add(j)
Next
Else
convValidChars.Add(AscW(Filter(k)))
End If
Next
Dim matchFound As Boolean = False
For Each indvUCC In cntrl.Text
For Each indvVC In convValidChars
matchFound = False
Dim indvUCCINT As Integer = Asc(indvUCC)
If indvVC = indvUCCINT Then
matchFound = True
Exit For
Else
If Case_Insensitive = True Then
If indvUCCINT >= 65 AndAlso indvUCCINT <= 90 Then
indvUCCINT = Asc(indvUCC.ToString.ToLower)
ElseIf indvUCCINT >= 97 AndAlso indvUCCINT <= 122 Then
indvUCCINT = Asc(indvUCC.ToString.ToUpper)
End If
If indvVC = indvUCCINT Then
matchFound = True
Exit For
End If
End If
End If
Next
If matchFound = False Then
Dim txtbox = TryCast(cntrl, TextBox)
If txtbox IsNot Nothing Then
txtbox.Focus()
txtbox.SelectAll()
End If
Return_Message = {cntrl.Name, indvUCC}
Return False
End If
Next
newPosition += 1
Next
Return True
End Function
End Class
Example usage:
Imports System.Windows.Forms
Imports Form1.InputVerification
Public Class test
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim filter_Test As New InputVerification
filter_Test.Controls = {TextBox1, TextBox2}
filter_Test.Filter = {2, "a-z", "0-9", 1, "0-9"}
filter_Test.Case_Insensitive = Yes
If filter_Test.InputFilter() = False Then
Dim respCTRL As String = filter_Test.Return_Message(0)
Dim respChar As String = filter_Test.Return_Message(1)
MsgBox("Control " & respCTRL & " has an invalid character, which is " & respChar)
End If
End Sub
End Class
I have it far better written up here, as it's a bit confusing to use at first.
InputVerification Thread

Force datagridviewcell that host a numeric updown revert it changed on escape key press

I'm creating a datagridviewcell that host a numeric updown control. Everything went fine except one thing. I can't revert changed on escape key press like textboxcell or comboboxcell. My datagridviewcell was created base on this example. So anyone have any idea how to revert numeric updown cell to previous value on escape key press?
NumericColumn class:
Imports System
Imports System.Windows.Forms
Public Class NumericColumn
Inherits DataGridViewColumn
''' <summary>
''' Get, set numeric control min value
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property MinValue() As Decimal
Get
Return CType(MyBase.CellTemplate, NumericCell).MinValue
End Get
Set(ByVal value As Decimal)
CType(MyBase.CellTemplate, NumericCell).MinValue = value
End Set
End Property
''' <summary>
''' Get, set numeric control max value
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property MaxValue() As Decimal
Get
Return CType(MyBase.CellTemplate, NumericCell).MaxValue
End Get
Set(ByVal value As Decimal)
CType(MyBase.CellTemplate, NumericCell).MaxValue = value
End Set
End Property
''' <summary>
''' Get, set numeric control value
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property NumericControlValue() As Decimal
Get
Return CType(MyBase.CellTemplate, NumericCell).NumericControlValue
End Get
Set(ByVal value As Decimal)
CType(MyBase.CellTemplate, NumericCell).NumericControlValue = value
End Set
End Property
''' <summary>
''' Indicate number of decimal places to display
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property DecimalPlaces() As Integer
Get
Return CType(MyBase.CellTemplate, NumericCell).DecimalPlaces
End Get
Set(ByVal value As Integer)
CType(MyBase.CellTemplate, NumericCell).DecimalPlaces = value
End Set
End Property
''' <summary>
''' Detemine the value to increment or decrement each time button click
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property Increment() As Integer
Get
Return CType(MyBase.CellTemplate, NumericCell).Increment
End Get
Set(ByVal value As Integer)
CType(MyBase.CellTemplate, NumericCell).Increment = value
End Set
End Property
Public Sub New()
MyBase.New(New NumericCell())
End Sub
Public Overrides Property CellTemplate() As DataGridViewCell
Get
Return MyBase.CellTemplate
End Get
Set(ByVal value As DataGridViewCell)
' Ensure that the cell used for the template is a CalendarCell.
If (value IsNot Nothing) AndAlso _
Not value.GetType().IsAssignableFrom(GetType(NumericCell)) _
Then
Throw New InvalidCastException("Must be a Numeric Cell")
End If
MyBase.CellTemplate = value
End Set
End Property
''' <summary>
''' Override clone method to clone new added properties
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Public Overrides Function Clone() As Object
Dim obj As NumericColumn = MyBase.Clone()
obj.MaxValue = Me.MaxValue
obj.MinValue = Me.MinValue
obj.NumericControlValue = Me.NumericControlValue
obj.DecimalPlaces = Me.DecimalPlaces
obj.Increment = Me.Increment
Return obj
End Function
End Class
NumericCell class
Imports System
Imports System.Windows.Forms
Public Class NumericCell
Inherits DataGridViewTextBoxCell
''' <summary>
''' Min value for numeric control
''' </summary>
''' <remarks></remarks>
Private min As Decimal = 0.0
''' <summary>
''' Max value for numeric control
''' </summary>
''' <remarks></remarks>
Private max As Decimal = 100.0
''' <summary>
''' Value for numeric control
''' </summary>
''' <remarks></remarks>
Private controlValue As Decimal = 0.0
''' <summary>
''' Decimal places for numeric control
''' </summary>
''' <remarks></remarks>
Private places As Integer = 0
''' <summary>
''' Detemine the value to increment or decrement each time button click
''' </summary>
''' <remarks></remarks>
Private incrementStep As Integer = 1
''' <summary>
''' Get, set numeric control min value
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property MinValue() As Decimal
Get
Return Me.min
End Get
Set(ByVal value As Decimal)
Me.min = value
End Set
End Property
''' <summary>
''' Get, set numeric control max value
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property MaxValue() As Decimal
Get
Return Me.max
End Get
Set(ByVal value As Decimal)
Me.max = value
End Set
End Property
''' <summary>
''' Get, set numeric control value
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property NumericControlValue() As Decimal
Get
Return Me.controlValue
End Get
Set(ByVal value As Decimal)
Me.controlValue = value
End Set
End Property
''' <summary>
''' Indicate number of decimal places to display
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property DecimalPlaces() As Integer
Get
Return Me.places
End Get
Set(ByVal value As Integer)
Me.places = value
End Set
End Property
''' <summary>
''' Detemine the value to increment or decrement each time button click
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property Increment() As Integer
Get
Return Me.incrementStep
End Get
Set(ByVal value As Integer)
Me.incrementStep = value
End Set
End Property
Public Sub New()
End Sub
Public Overrides Sub InitializeEditingControl(ByVal rowIndex As Integer, _
ByVal initialFormattedValue As Object, _
ByVal dataGridViewCellStyle As DataGridViewCellStyle)
' Set the value of the editing control to the current cell value.
MyBase.InitializeEditingControl(rowIndex, initialFormattedValue, _
dataGridViewCellStyle)
Dim ctl As NumericEditingControl = CType(DataGridView.EditingControl, NumericEditingControl)
RemoveHandler ctl.Enter, AddressOf Me.OnNumericEnter
AddHandler ctl.Enter, AddressOf Me.OnNumericEnter
'config property for control
ctl.Minimum = Me.min
ctl.Maximum = Me.max
ctl.DecimalPlaces = Me.DecimalPlaces
ctl.Increment = Me.incrementStep
ctl.TextAlign = HorizontalAlignment.Right
ctl.ThousandsSeparator = True
' Use the default row value when Value property is null.
If (Me.Value Is Nothing) Then
ctl.Value = Me.controlValue
Else
ctl.Value = CType(Me.Value, Decimal)
End If
End Sub
''' <summary>
''' Handle on enter event of numeric
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub OnNumericEnter(ByVal sender As Object, ByVal e As EventArgs)
Dim control As NumericEditingControl = CType(sender, NumericEditingControl)
Dim strValue As String = control.Value.ToString("N2")
control.Select(0, strValue.Length)
End Sub
Public Overrides ReadOnly Property EditType() As Type
Get
' Return the type of the editing control that CalendarCell uses.
Return GetType(NumericEditingControl)
End Get
End Property
Public Overrides ReadOnly Property ValueType() As Type
Get
' Return the type of the value that CalendarCell contains.
Return GetType(String)
End Get
End Property
Public Overrides ReadOnly Property DefaultNewRowValue() As Object
Get
' Use the current date and time as the default value.
Return 0.0
End Get
End Property
''' <summary>
''' Override clone method to clone new added properties
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Public Overrides Function Clone() As Object
Dim obj As NumericCell = MyBase.Clone()
obj.MaxValue = Me.MaxValue
obj.MinValue = Me.MinValue
obj.NumericControlValue = Me.NumericControlValue
obj.DecimalPlaces = Me.DecimalPlaces
obj.Increment = Me.Increment
Return obj
End Function
End Class
NumericEditingControl class:
Imports System
Imports System.Windows.Forms
Public Class NumericEditingControl
Inherits NumericUpDown
Implements IDataGridViewEditingControl
Private dataGridViewControl As DataGridView
Private valueIsChanged As Boolean = False
Private rowIndexNum As Integer
Public Sub New()
'Me.Format = DateTimePickerFormat.Short
End Sub
Public Property EditingControlFormattedValue() As Object _
Implements IDataGridViewEditingControl.EditingControlFormattedValue
Get
Return Me.Value.ToString("N2")
End Get
Set(ByVal value As Object)
Try
' This will throw an exception of the string is
' null, empty, or not in the format of a date.
Me.Value = Decimal.Parse(value)
Catch
' In the case of an exception, just use the default
' value so we're not left with a null value.
Me.Value = 0.0
End Try
End Set
End Property
Public Function GetEditingControlFormattedValue(ByVal context _
As DataGridViewDataErrorContexts) As Object _
Implements IDataGridViewEditingControl.GetEditingControlFormattedValue
Return Me.Value.ToString("N2")
End Function
Public Sub ApplyCellStyleToEditingControl(ByVal dataGridViewCellStyle As _
DataGridViewCellStyle) _
Implements IDataGridViewEditingControl.ApplyCellStyleToEditingControl
Me.Font = dataGridViewCellStyle.Font
Me.ForeColor = dataGridViewCellStyle.ForeColor
Me.BackColor = dataGridViewCellStyle.BackColor
End Sub
Public Property EditingControlRowIndex() As Integer _
Implements IDataGridViewEditingControl.EditingControlRowIndex
Get
Return rowIndexNum
End Get
Set(ByVal value As Integer)
rowIndexNum = value
End Set
End Property
Public Function EditingControlWantsInputKey(ByVal key As Keys, _
ByVal dataGridViewWantsInputKey As Boolean) As Boolean _
Implements IDataGridViewEditingControl.EditingControlWantsInputKey
' Let the DateTimePicker handle the keys listed.
'Select Case key And Keys.KeyCode
' Case Keys.Left, Keys.Up, Keys.Down, Keys.Right, _
' Keys.Home, Keys.End, Keys.PageDown, Keys.PageUp
' Return True
' Case Else
' Return Not dataGridViewWantsInputKey
'End Select
If key.KeyCode = Keys.Escape Then
End If
Return True
End Function
Public Sub PrepareEditingControlForEdit(ByVal selectAll As Boolean) _
Implements IDataGridViewEditingControl.PrepareEditingControlForEdit
' No preparation needs to be done.
End Sub
Public ReadOnly Property RepositionEditingControlOnValueChange() _
As Boolean Implements _
IDataGridViewEditingControl.RepositionEditingControlOnValueChange
Get
Return False
End Get
End Property
Public Property EditingControlDataGridView() As DataGridView _
Implements IDataGridViewEditingControl.EditingControlDataGridView
Get
Return dataGridViewControl
End Get
Set(ByVal value As DataGridView)
dataGridViewControl = value
End Set
End Property
Public Property EditingControlValueChanged() As Boolean _
Implements IDataGridViewEditingControl.EditingControlValueChanged
Get
Return valueIsChanged
End Get
Set(ByVal value As Boolean)
valueIsChanged = value
End Set
End Property
Public ReadOnly Property EditingControlCursor() As Cursor _
Implements IDataGridViewEditingControl.EditingPanelCursor
Get
Return MyBase.Cursor
End Get
End Property
Protected Overrides Sub OnValueChanged(ByVal eventargs As EventArgs)
' Notify the DataGridView that the contents of the cell have changed.
valueIsChanged = True
Me.EditingControlDataGridView.NotifyCurrentCellDirty(True)
MyBase.OnValueChanged(eventargs)
End Sub
End Class
The part responsible to deal with this behaviour is EditingControlWantsInputKey. By looking at the original code it is clear that this part has to be set by default to false (= returning to the previously stored value), but in your code it is set to true. The idea is setting this to true only for ("special") keys which shouldn't provoke the scaping of the value; that is, you don't need to mention here scape, just any other key (triggering this function) which you don't want to provoke the coming-back-to-previous-value behaviour.
Thus, solution:
Public Function EditingControlWantsInputKey(ByVal key As Keys, _
ByVal dataGridViewWantsInputKey As Boolean) As Boolean _
Implements IDataGridViewEditingControl.EditingControlWantsInputKey
Return False
End Function

Asynchronous Progress bar updating

This is a vb.net mvc 3 application.. I am new to asynchronous and threading combined so this is a bit over my head on 2 levels... I have a long running process that sends mass emails at set intervals to avoid terms of use violations.. Not only for this task but for other options I would like to add a progress bar that is updated through java..I have found a blog post about doing something like this... I have got the following code but there seems to be an issue where the progress bar is never showing...
Below is my extendedTaskRun Class:
Imports System.Collections.Generic
Imports System.Linq
Imports System.Threading
Namespace ExtendedTaskHandler
''' <summary>
''' Long Running Test Class.
''' </summary>
Public Class extendedTaskRun
Private Shared syncRoot As New Object()
''' <summary>
''' Gets or sets the process status.
''' </summary>
''' <value>The process status.</value>
Private Shared Property ProcessStatus() As IDictionary(Of String, Integer)
Get
Return m_ProcessStatus
End Get
Set(value As IDictionary(Of String, Integer))
m_ProcessStatus = value
End Set
End Property
Private Shared m_ProcessStatus As IDictionary(Of String, Integer)
''' <summary>
''' Initializes a new instance of the <see cref="extendedTaskRun"/> class.
''' </summary>
Public Sub New()
If ProcessStatus Is Nothing Then
ProcessStatus = New Dictionary(Of String, Integer)()
End If
End Sub
Public Sub SetStatus(ByVal id As String, ByVal value As Integer)
SyncLock syncRoot
ProcessStatus(id) = value
End SyncLock
End Sub
''' <summary>
''' Processes the long running action.
''' </summary>
''' <param name="id">The id.</param>
Public Function ProcessLongRunningAction(id As String) As String
For i As Integer = 1 To 100
Thread.Sleep(100)
SyncLock syncRoot
ProcessStatus(id) = i
End SyncLock
Next
Return id
End Function
''' <summary>
''' Adds the specified id.
''' </summary>
''' <param name="id">The id.</param>
Public Sub Add(id As String)
SyncLock syncRoot
ProcessStatus.Add(id, 0)
End SyncLock
End Sub
''' <summary>
''' Removes the specified id.
''' </summary>
''' <param name="id">The id.</param>
Public Sub Remove(id As String)
SyncLock syncRoot
ProcessStatus.Remove(id)
End SyncLock
End Sub
''' <summary>
''' Gets the status.
''' </summary>
''' <param name="id">The id.</param>
Public Function GetStatus(id As String) As Integer
SyncLock syncRoot
If ProcessStatus.Keys.Where(Function(x) x = id).Count = 1 Then
Return ProcessStatus(id)
Else
Return 100
End If
End SyncLock
End Function
End Class
End Namespace
Then my controllers are as follows:
Public Function MassEmailStatus() As ActionResult
MassEmailAddressList = TempData("emailaddresses")
TempData.Clear()
TempData.Add("emailaddresses", MassEmailAddressList)
Return View()
End Function
Public Function MassEmailSendingStatus(ByVal id As String) As ActionResult
Dim d As List(Of String) = TempData("emList")
Dim EmailCount As Integer = d.Count
Dim triedCount As Integer = 0
Dim extendedTaskRun As New extendedTaskRun
extendedTaskRun.Add(id)
Dim percentDone As Integer = 0
While Not (triedCount = EmailCount)
For Each em In d
EmailSender(em, String.Empty)
triedCount += 1
percentDone = EmailCount / 100 + triedCount
extendedTaskRun.SetStatus(id, percentDone)
Next
End While
extendedTaskRun.Remove(id)
Return View()
End Function
Then the MassEmailStatus view is as follows:
#Code
ViewData("Title") = "MassEmailSendingStatus"
TempData.Add("emList", TempData("emailaddresses"))
end Code
<div>
Start Long Running Process
</div>
<br />
<div id="statusBorder">
<div id="statusFill">
</div>
</div>
<script type="text/javascript">
var uniqueId = '#Guid.NewGuid().ToString()';
var tdata = '#TempData("emailaddresses")';
$(document).ready(function (event) {
$('#startProcess').click(function () {
$.post("MassEmailSendingStatus", { id: uniqueId }, function () {
$('#statusBorder').show();
getStatus();
});
event.preventDefault;
});
});
function getStatus() {
var url = 'Admin/GetCurrentProgress/' + uniqueId;
$.get(url, function (data) {
if (data != "100") {
$('#status').html(data);
$('#statusFill').width(data);
window.setTimeout("getStatus()", 100);
}
else {
$('#status').html("Done");
$('#statusBorder').hide();
alert("The Long process has finished");
};
});
}
</script>
These are the additional functions that the blog mentioned and are in my code but from looking at the code I know they cannot be correctly wired up.
Private Delegate Function ProcessTask(id As String) As String
Private extendedRunClass As New extendedTaskRun
''' <summary>
''' Starts the long running process.
''' </summary>
''' <param name="id">The id.</param>
Public Sub StartLongRunningProcess(id As String)
extendedRunClass.Add(id)
Dim processTask As New ProcessTask(AddressOf extendedRunClass.ProcessLongRunningAction)
processTask.BeginInvoke(id, New AsyncCallback(AddressOf EndLongRunningProcess), processTask)
End Sub
''' <summary>
''' Ends the long running process.
''' </summary>
''' <param name="result">The result.</param>
Public Sub EndLongRunningProcess(result As IAsyncResult)
Dim processTask As ProcessTask = DirectCast(result.AsyncState, ProcessTask)
Dim id As String = processTask.EndInvoke(result)
extendedRunClass.Remove(id)
End Sub
''' <summary>
''' Gets the current progress.
''' </summary>
''' <param name="id">The id.</param>
Public Function GetCurrentProgress(id As String) As ContentResult
Me.ControllerContext.HttpContext.Response.AddHeader("cache-control", "no-cache")
Dim currentProgress = extendedRunClass.GetStatus(id).ToString()
Return Content(currentProgress)
End Function
I do know that Im not actually starting the process as im just calling EmailSender(em, String.Empty) which is where the work occurs, inside the for each loop of the MassEmailSendingStatus controller... What must I do to fix this correctly?
WOW my code was whacked...After taking the blog code and throwing it in a quick project of its own and starting it i was able to watch what was happening.. I have it working now... I will update this with the working solution in a bit... Working on returning more than just percentage to the progress bar now so messages are displayed as its working.. Not sure how im going to do that but im thinking I will do it inside the getCurrentProgress method as a string return from the extendedTaskRun class...