Using RFID in multiple windows forms - vb.net

Hie there.
I am trying to use RFID tags on different forms. The code I have works fine if in one from. As soon you add it to another form it stops. I have tried using event handlers to no success. Does anyone know how I coud do this.
Here is my code:
Public Class Form1
Dim WithEvents phidgetRFID As Phidgets.RFID
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'To reduce code complexity we assume that there is one PhidgetRFID
'attached to the PC before the program is run.
phidgetRFID = New Phidgets.RFID()
phidgetRFID.Open()
'Defaults for text fields
txtStatus.Text = "Not Connected"
End Sub
Public Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
lvPhidgetInfo.MultiColumn = False
lvPhidgetInfo.Items.Insert(0, "TagID Count")
End Sub
Private Sub phidgetRFID_Attach(ByVal sender As Object, ByVal e As Phidgets.Events.AttachEventArgs) Handles phidgetRFID.Attach
'When the Phidget RFID attaches update the form text boxes
Label1.Text = "Phidget RFID Reader has Attached"
txtStatus.Text = "Connected"
txtNumOutputs.Text = phidgetRFID.outputs.Count
txtSerialNumber.Text = (Str(phidgetRFID.SerialNumber))
phidgetRFID.Antenna = True
CheckBox3.Checked = True
phidgetRFID.LED = True
CheckBox2.Checked = True
End Sub
Private Sub phidgetRFID_Detach(ByVal sender As Object, ByVal e As Phidgets.Events.DetachEventArgs) Handles phidgetRFID.Detach
'If the Phidget RFID detaches close the form
Me.Close()
End Sub
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
'If the form closes and the Phidget RFID is attached Close it.
If phidgetRFID.Attached = True Then
phidgetRFID.close()
End If
End Sub
Private Sub phidgetRFID_Error(ByVal sender As Object, ByVal e As Phidgets.Events.ErrorEventArgs) Handles phidgetRFID.Error
'If the Phidget RFID is not attached when the form opens show
'message box and close the form
MessageBox.Show(e.Description)
Me.Close()
End Sub
Private Sub phidgetRFID_RFIDTag(ByVal sender As Object, ByVal e As Phidgets.Events.TagEventArgs) Handles phidgetRFID.Tag
Static count As Integer
count = count + 1
lvPhidgetInfo.BeginUpdate()
lvPhidgetInfo.Items.Insert(1, e.Tag & " " & count)
lvPhidgetInfo.EndUpdate()
End Sub
Private Sub phidgetRFID_RFIDTagLost(ByVal sender As Object, ByVal e As Phidgets.Events.TagEventArgs) Handles phidgetRFID.TagLost
lvPhidgetInfo.BeginUpdate()
lvPhidgetInfo.Items.Insert(1, e.Tag & " Lost")
lvPhidgetInfo.EndUpdate()
End Sub
I have also tried this and I crushes without reporting an error.
Dim PhidgetRFID As New Phidgets.RFID()
AddHandler PhidgetRFID.Attach, AddressOf rfid_Attach
AddHandler PhidgetRFID.Detach, AddressOf rfid_Detach
AddHandler PhidgetRFID.Tag, AddressOf rfid_Tag
AddHandler PhidgetRFID.TagLost, AddressOf rfid_TagLost
AddHandler PhidgetRFID.Error, AddressOf rfid_Error
PhidgetRFID.open()
PhidgetRFID.waitForAttachment(3000)
Private Sub rfid_Attach(sender As Object, e As AttachEventArgs)
Label3.Text = "RFID reader {0} attached!" & e.Device.SerialNumber.ToString()
'Throw New NotImplementedException
End Sub
Private Sub rfid_Detach(sender As Object, e As DetachEventArgs)
Label4.Text = "RFID reader {0} ditached!" & e.Device.SerialNumber.ToString()
End Sub
Private Sub rfid_Tag(sender As Object, e As TagEventArgs)
Try
txtCardNumber.Text = e.Tag
Dim lastRFIDTag As String = txtCardNumber.Text
phidgetRFID.LED = True
' Throw New NotImplementedException
Catch ex As Exception
MsgBox("" & ex.Message, , "")
End Try
End Sub
Private Sub rfid_TagLost(sender As Object, e As TagEventArgs)
'Throw New NotImplementedException
phidgetRFID.LED = False
End Sub
Plaese help..

Related

Running an external app in textbox (how to preserve all functionality?)

I'm trying to run a cmd like application (so no GUI) in my form. In the example down below I called it ExternalApp.exe. The code itself works; I can send commands to it by entering them in TextBox2. The issue is that ExternalApp normally uses a command prompt and supports things like displaying one single screen of output and then wait for an enter before showing the next one. This is no longer working, all output is sent to TextBox1 all at once.
Is there any way to have ExternalApp behave like it normally does? I hope I'm explained myself a bit clear. Thanks for any help in advance!
Kind regards,
Eric
Public Class Form1
Dim WithEvents P As New Process
Dim SW As System.IO.StreamWriter
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
P.EnableRaisingEvents = True
Me.Text = "My title"
AddHandler P.OutputDataReceived, AddressOf DisplayOutput
P.StartInfo.CreateNoWindow() = True
P.StartInfo.UseShellExecute = False
P.StartInfo.RedirectStandardInput = True
P.StartInfo.RedirectStandardOutput = True
P.StartInfo.FileName = "ExternalApp.exe"
P.StartInfo.Arguments = ""
P.Start()
P.SynchronizingObject = Me
P.BeginOutputReadLine()
SW = P.StandardInput
SW.WriteLine()
End Sub
Private Sub DisplayOutput(ByVal sendingProcess As Object, ByVal output As DataReceivedEventArgs)
TextBox1.AppendText(output.Data() & vbCrLf)
End Sub
Private Sub Textbox2_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox2.KeyPress
If e.KeyChar = Chr(Keys.Return) Then
SW.WriteLine(TextBox2.Text)
End If
End Sub
Private Sub myProcess_Exited(ByVal sender As Object, ByVal e As System.EventArgs) Handles P.Exited
Me.Close()
End Sub End Class

VB.Net Send output and input of process started in another form

I have 2 forms, MainForm and RCONForm.
What I am trying to do is to start a process when the programs starts and in this case I have choosen cmd.exe and it works.
The thing is I want to be able to read the output and send input onto the process from another form using 2 textboxes.
The problem is that I can't read anything from the process neither can I send any input to it either.
My MainForm:
Public Class MainForm
#Region "Import Function"
Dim Functions As New Functions
Friend WithEvents RCON As Process
#End Region
Friend Sub AppendOutputText(ByVal text As String)
If RCONForm.RCONLogText.InvokeRequired Then
Dim myDelegate As New RCONForm.AppendOutputTextDelegate(AddressOf AppendOutputText)
Me.Invoke(myDelegate, text)
Else
RCONForm.RCONLogText.AppendText(text)
End If
End Sub
Private Sub MainForm_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
RCON = New Process
With RCON.StartInfo
.FileName = "C:\Windows\system32\CMD.exe"
.UseShellExecute = False
.CreateNoWindow = True
.RedirectStandardInput = True
.RedirectStandardOutput = True
.RedirectStandardError = True
End With
RCON.Start()
RCON.BeginErrorReadLine()
RCON.BeginOutputReadLine()
AppendOutputText("RCON Started at: " & RCON.StartTime.ToString)
End Sub
Private Sub RCONButton_Click(sender As Object, e As EventArgs) Handles RCONButton.Click
Functions.KillOldForm()
Functions.SpawnForm(Of RCONForm)()
End Sub
Private Sub ExitButton_Click(sender As Object, e As EventArgs) Handles ExitButton.Click
Application.Exit()
End Sub
Private Sub ServerButton_Click(sender As Object, e As EventArgs) Handles ServerButton.Click
Functions.KillOldForm()
Functions.SpawnForm(Of ServerForm)()
End Sub
End Class
And my RCONForm:
Public Class RCONForm
Friend Delegate Sub AppendOutputTextDelegate(ByVal text As String)
Friend WithEvents RCON As Process = MainForm.RCON
Friend Sub RCON_ErrorDataReceived(ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs) Handles RCON.ErrorDataReceived
MainForm.AppendOutputText(vbCrLf & "Error: " & e.Data)
End Sub
Friend Sub RCON_OutputDataReceived(ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs) Handles RCON.OutputDataReceived
MainForm.AppendOutputText(vbCrLf & e.Data)
End Sub
Friend Sub RCONCommandText_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles RCONCommandText.KeyPress
If e.KeyChar = Microsoft.VisualBasic.ChrW(Keys.Return) Then
MainForm.RCON.StandardInput.WriteLine(RCONCommandText.Text)
MainForm.RCON.StandardInput.Flush()
RCONCommandText.Text = ""
e.Handled = True
End If
End Sub
Friend Sub RCONForm_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
MainForm.RCON.StandardInput.WriteLine("EXIT") 'send an EXIT command to the Command Prompt
MainForm.RCON.StandardInput.Flush()
MainForm.RCON.Close()
End Sub
Private Sub RCONForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
End Class
My Functions:
#Region "Kill Old Forms"
Function KillOldForm()
While MainForm.SpawnPanel.Controls.Count > 0
MainForm.SpawnPanel.Controls(0).Dispose()
End While
Return Nothing
End Function
#End Region
#Region "Spawn Form"
Function SpawnForm(Of T As {New, Form})() As T
Dim spawn As New T() With {.TopLevel = False, .AutoSize = False}
Try
spawn.Dock = DockStyle.Fill
MainForm.SpawnPanel.Controls.Add(spawn)
spawn.Show()
Catch ex As Exception
MsgBox(ex.Message)
End Try
Return Nothing
End Function
#End Region
I have been thinking of using threads and maybe that can solve the issue, or is there a more simple way?
You are using default form instances heavily. You should avoid that if possible. Here's a way to keep track of the proper instance of RCONForm in MainForm
Private myRCONForm As RCONForm
Private Sub RCONButton_Click(sender As Object, e As EventArgs) Handles RCONButton.Click
Functions.KillOldForm()
myRCONForm = Functions.SpawnForm(Of RCONForm)()
End Sub
Now SpawnForm is a function, and it would return the form so you can keep a reference to it
Public Function SpawnForm(Of T As {New, Form})() As T
Dim myForm = New T()
' add myForm to the appropriate Panel or whatever
Return myForm
End Function
Update all access to RCONForm with myRCONForm in MainForm
Also, this is a little flawed, where you check if invocation is required on RCONForm.RCONLogText, then invoke on Me. It can be simplified
' old with default form instance
Friend Sub AppendOutputText(ByVal text As String)
If RCONForm.RCONLogText.InvokeRequired Then
Dim myDelegate As New RCONForm.AppendOutputTextDelegate(AddressOf AppendOutputText)
Me.Invoke(myDelegate, text)
Else
RCONForm.RCONLogText.AppendText(text)
End If
End Sub
' new, with instance reference plus simplified invocation
Friend Sub AppendOutputText(text As String)
If myRCONForm.RCONLogText.InvokeRequired Then
myRCONForm.RCONLogText.Invoke(New Action(Of String)(AddressOf AppendOutputText), text)
Else
myRCONForm.RCONLogText.AppendText(text)
End If
End Sub

"For Each" loop : Application Freeze in Vb.net

I am using the following code to get the size of files inside a directory
and put it in Label1:
For Each foundFile As String In My.Computer.FileSystem.GetFiles( _
"\windows",Microsoft.VisualBasic.FileIO.SearchOption.SearchTopLevelOnly,_
"*.*")
Dim filesizelabel As System.IO.FileInfo = My.Computer.FileSystem.GetFileInfo(foundFile)
Label1.Text = Label1.Text + filesizelabel.Length
Next
The problem is that i have more than 50 for each loops (a system cleaning app).
When I run the loops my app freezes until the loops finish, even if I run one loop.
Is there a solution to make it show the name of the current file? I tried this as well, but it also froze my application:
label2.text = foundfile
The application does not respond to any click, until it finishes the loops. It shows the size in Label1 and the last scanned file in Label2. This also freezes the application:
system.threading.thread.sleep(100)
Is there any alternative to foreach or a solution to fix this issue?
Here's a quick example using Async/Await with a Button Click() Handler:
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Button1.Enabled = False
Await Task.Run(Sub()
' this runs in a different thread without blocking the GUI:
For Each foundFile As String In My.Computer.FileSystem.GetFiles(
"\windows", Microsoft.VisualBasic.FileIO.SearchOption.SearchTopLevelOnly, "*.*")
Dim filesizelabel As System.IO.FileInfo = My.Computer.FileSystem.GetFileInfo(foundFile)
' when you need to update the GUI:
Me.Invoke(Sub()
' ... do it in here ...
Label1.Text = Label1.Text + filesizelabel.Length
End Sub)
Next
End Sub)
Button1.Enabled = True
End Sub
For VB.Net 2010, try this instead:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Button1.Enabled = False
Dim T As New System.Threading.Thread(AddressOf Worker)
T.Start()
End Sub
Private Sub Worker()
' this runs in a different thread without blocking the GUI:
For Each foundFile As String In My.Computer.FileSystem.GetFiles(
"\windows", Microsoft.VisualBasic.FileIO.SearchOption.SearchTopLevelOnly, "*.*")
Dim filesizelabel As System.IO.FileInfo = My.Computer.FileSystem.GetFileInfo(foundFile)
' when you need to update the GUI:
Me.Invoke(Sub()
' ... do it in here ...
Label1.Text = Label1.Text + filesizelabel.Length
End Sub)
Next
Me.Invoke(Sub()
Button1.Enabled = True
End Sub)
End Sub
This is a prime candidate for a background worker.
Have a read about how they work, but at a high level the task is run in another thread with some events that you access in your main UI thread.
Private bw As BackgroundWorker = New BackgroundWorker
Private Sub buttonStart_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
If Not bw.IsBusy = True Then
' this will start the work
bw.RunWorkerAsync()
End If
End Sub
Private Sub buttonCancel_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
If bw.WorkerSupportsCancellation = True Then
' this will allow the user to cancel the work part way through
bw.CancelAsync()
End If
End Sub
Private Sub bw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
' your slow code goes here
End Sub
Private Sub bw_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
' you can update the UI here to show progress
End Sub
Private Sub bw_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
' your 'I've finished notification' code goes here
End Sub
Derek has put a bad code, it's not working and Idle mind code does not work on .NET 2.0
Dereks approach is working if code is complete, as below:
Private bw As BackgroundWorker = New BackgroundWorker
Private Sub app_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AddHandler bw.DoWork, AddressOf bw_DoWork
AddHandler bw.ProgressChanged, AddressOf bw_ProgressChanged
AddHandler bw.RunWorkerCompleted, AddressOf bw_RunWorkerCompleted
..
End sub
Private Sub Btn_Click(sender As Object, e As EventArgs) Handles Btn.Click
If Not bw.IsBusy = True Then
' this will start the work
bw.RunWorkerAsync()
End If
End Sub
Private Sub bw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
'your work to not freeze form
end sub
Private Sub bw_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
' you can update the UI here to show progress
End Sub
Private Sub bw_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
' your 'I've finished notification' code goes here
End Sub

combobox multiple thread error

I have a problem with my code. I keep getting Multiple thread Error with backgroundworker, because of the combobox item display. Please look at my code below its a very simple code which I am planning to use on big scale, all I want it to do is "If item "1" selected show item "1" in label1. I can only assume that problem exists because Combobox runs in different thread....
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
BackgroundWorker1.runworkerasync()
BackgroundWorker1.WorkerReportsProgress = True
Me.Cursor = Cursors.WaitCursor 'Cursor changes to wait
End Sub
Public Structure controlwithtext
Public controlname As Control
Public text As String
Public Sub New(ByVal ctrl As Control, ByVal text As String)
Me.controlname = ctrl
Me.text = text
End Sub
End Structure
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
If comboBox1.SelectedItem = "1" then
BackgroundWorker1.ReportProgress(5, New controlwithtext(Label1, ComboBox1.SelectedItem))
End If
End Sub
Private Sub SetBackgroundWorker_ProgressChanged(ByVal sender As Object,
ByVal e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
If TypeOf e.UserState Is controlwithtext Then
Dim cwt As controlwithtext = CType(e.UserState, controlwithtext)
cwt.controlname.Text = cwt.text
End If
End Sub
Here's an example of how to read from and write to controls from the BackgroundWorker thread:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
While True
System.Threading.Thread.Sleep(250)
Dim selection As String = Me.Invoke(Function()
If Not IsNothing(ComboBox1.SelectedItem) Then
Return ComboBox1.SelectedItem.ToString
Else
Return String.Empty
End If
End Function).ToString
If selection = "1" Then
Me.Invoke(Sub()
Label1.Text = ComboBox1.SelectedItem.ToString
End Sub)
Else
Me.Invoke(Sub()
Label1.Text = "something else"
End Sub)
End If
End While
End Sub

Very basic VB.Net & Serial IO issue

After searching around I am still having issues with reading data from a serial port in VB.Net/VS2010. I know the Serial Port works, I can write to the port fine but when reading from it, nothing happens. I have only been programming for the last 3 weeks so am still trying to get my head around it all.
The program must run to capture data from a door logger, I will then be outputting the data to a database (not yet implemented - I want to get this part sorted first).
I have tried using several terminal programs as well as another device which outputs data onto the serial line, with nothing displaying in the textbox tbxIn.
Any help would be greatly appreciated.
Code is below:
Imports System.IO.Ports
Imports System.IO.Ports.SerialPort
Public Class Form1
Dim comPort As IO.Ports.SerialPort = Nothing
Dim sComPort As String = ""
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
GetSerialPortNames()
End Sub
Sub GetSerialPortNames()
' Show all available COM ports.
For Each sp As String In My.Computer.Ports.SerialPortNames
lstPorts.Items.Add(sp)
Next
End Sub
Private Sub lstPorts_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lstPorts.SelectedIndexChanged
sComPort = lstPorts.SelectedItem
Button1.Enabled = True
End Sub
Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
' Open the serial port using the OpenSerialPort method
Button1.Enabled = False
Button2.Enabled = True
Try
comPort = My.Computer.Ports.OpenSerialPort(sComPort, 9600, IO.Ports.Parity.None, 8, 1)
' comPort.DtrEnable = True
comPort.ReadTimeout = 500
Do
comPort.WriteLine("Go")
Dim sIncomming As String = comPort.ReadLine()
tbxIn.Text = sIncomming & vbCrLf
Loop
Catch ex As TimeoutException
tbxIn.Text &= "Error: Serial Port Read Timeout" & vbCrLf
End Try
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
comPort.Close()
Button1.Enabled = True
Button2.Enabled = False
End Sub
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
tbxIn.Text = e.ToString
End Sub
End Class
PRetty sure this will get you what you need. You DON't need the Serial1 component on the designer. Remove that and use this code:
Private comPort As IO.Ports.SerialPort = Nothing
Private sComPort As String = ""
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)
GetSerialPortNames()
End Sub
Sub GetSerialPortNames()
' Show all available COM ports.
For Each sp As String In My.Computer.Ports.SerialPortNames
lstPorts.Items.Add(sp)
Next
End Sub
Private Sub lstPorts_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lstPorts.SelectedIndexChanged
sComPort = lstPorts.SelectedItem
Button1.Enabled = True
End Sub
Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
' Open the serial port using the OpenSerialPort method
Button1.Enabled = False
Button2.Enabled = True
Try
comPort = My.Computer.Ports.OpenSerialPort(sComPort, 9600, IO.Ports.Parity.None, 8, 1)
' comPort.DtrEnable = True
'must add handler
AddHandler comPort.DataReceived, AddressOf SerialPort1_DataReceived
comPort.ReadTimeout = 500
Do
comPort.WriteLine("Go")
Dim sIncomming As String = comPort.ReadLine()
tbxIn.Text = sIncomming & vbCrLf
Loop
Catch ex As TimeoutException
tbxIn.Text &= "Error: Serial Port Read Timeout" & vbCrLf
End Try
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
comPort.Close()
'remove handler
RemoveHandler comPort.DataReceived, AddressOf SerialPort1_DataReceived
Button1.Enabled = True
Button2.Enabled = False
End Sub
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs)
tbxIn.Text = e.ToString
End Sub