Have anyone idea why my code return "" inside my Textbox ? :-)
This i have in main Class
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim My_Thread as Threading.Thread
My_Thread = New Threading.Thread(AddressOf Module1.MyTest)
My_Thread.Start()
End Sub
And this in module1
Sub MyTest()
Dim TestingValue as string = "Test"
MainForm.Textbox1.Text = TestingValue
End sub
Invoke all time crash code and another try return "" inside texbox1 :-/
Create a Sub Class with public declarations to any object you want on MainForm, then pass the class as a parameter to the module. This would be a cleaner approach than passing the entire Form class instance. Then using the method that Jimi has suggested you can setyou textboxs without cross thread violation.
Public Class MainForm
Public Class PassToModule
Public TxBx1 As TextBox = MainForm.TextBox1
Public TxBx2 As TextBox = MainForm.TextBox2
End Class
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim PassToModule As New PassToModule
Dim My_Thread As Threading.Thread
My_Thread = New Threading.Thread(AddressOf MyTest)
My_Thread.Start(PassToModule)
End Sub
End Class
Module Module1
Dim FromMainForm As MainForm.PassToModule
Sub MyTest(PasToModule As MainForm.PassToModule)
FromMainForm = PasToModule
FromMainForm.TxBx1.BeginInvoke(New MethodInvoker(Sub()
FromMainForm.TxBx1.Text = "Test"
FromMainForm.TxBx2.Text = "Test"
End Sub))
End Sub
End Module
Related
I have three forms in total and i want to trigger one of the button on form 3 to be triggered automatically when form 1 loaded
Form 1
Public Class frmIOMain
' In This Form load I want to trigger the above mentioned button
Private Sub IOMain_Load(sender As Object, e As System.EventArgs) Handles Me.Load
' I want to Trigger the Above mentioned button here when my form is loaded
' But it is not working for me
frmUpdateDueDates.cmdUpdate_Click(Nothing, Nothing)
End Sub
End Class
Form 2
Public Class TestEquipmentManagement
Public EquipementTable As New DataTable("EquipmentTable")
Public EquiTypeSelection As String
Public EquiManufacturerSelection As String
Public EquiList_PK As New List(Of Integer)
Dim targetEquipmentList As New List(Of Model.equipment)
Private equipDB As Model.Entities = Nothing
Public Shared viewManager As ViewManager
Private equipment As New List(Of Model.equipment)
'Dim WithEvents excNewPFM As New VBACom
Public EquipCalTable As New DataTable("EquipCalTable")
Public Sub New()
Dim todayplusoneyear As Date
todayplusoneyear = Date.Today
todayplusoneyear = todayplusoneyear.AddYears(1)
'Assign current db
equipDB = frmIOMain.db
End Sub
End Class
Form 3
Public Class frmUpdateDueDates
Private EquipmentUpdates As UpdateCalibrationsViewModel
Private _success As Boolean = False
Public Sub New(db As Entities)
' Dieser Aufruf ist für den Designer erforderlich.
InitializeComponent()
EquipmentUpdates = New UpdateCalibrationsViewModel(db, New CAQ23(), False)
'Add Handlers
AddHandler EquipmentUpdates.OnProgressChanged, AddressOf progressChangedHandler
AddHandler EquipmentUpdates.OnInfotextChanged, AddressOf infoTextChangedHandler
prgUpdates.Maximum = EquipmentUpdates.intProgressMax
End Sub
Public Sub cmdUpdate_Click(sender As Object, e As EventArgs) Handles cmdUpdate.Click
cmdUpdate.Enabled = False
_success = EquipmentUpdates.startUpdating()
cmdCancel.Text = "Close"
End Sub
End Class
I want "cmdUpdate_Click" Button which is on form 3 to be triggered when my form 1 is loaded
Can Anyone tell me how i can do that?
Firstly, create an instance of the form, instead of using its default form instance. Calling a click handler across forms isn't a good idea. The handler may use the arguments sender As Object, e As EventArgs and from outside of the containing class, you can't assume you know that. Better practice would be to create a method which performs the click within the form, such as
Public Class frmUpdateDueDates
Public Sub cmdUpdateClick()
cmdUpdate.PerformClick()
End Sub
Private Sub cmdUpdate_Click(sender As Object, e As EventArgs) Handles cmdUpdate.Click
cmdUpdate.Enabled = False
_success = EquipmentUpdates.startUpdating()
cmdCancel.Text = "Close"
End Sub
End Class
Public Class frmIOMain
Private myFrmUpdateDueDates As frmUpdateDueDates
Private Sub IOMain_Load(sender As Object, e As System.EventArgs) Handles Me.Load
myFrmUpdateDueDates = New FrmUpdateDueDates()
myFrmUpdateDueDates.Show()
'myFrmUpdateDueDates.cmdUpdate_Click(Nothing, Nothing)
myFrmUpdateDueDates.cmdUpdateClick()
End Sub
End Class
And you can change the access modifier of the click handler back to Private
Even better would be to put the work into a different method which the click handler calls. Then the other form doesn't even need to know the button exists. Such as
Public Class frmUpdateDueDates
Public Sub DoUpdating()
cmdUpdate.Enabled = False
_success = EquipmentUpdates.startUpdating()
cmdCancel.Text = "Close"
End Sub
Private Sub cmdUpdate_Click(sender As Object, e As EventArgs) Handles cmdUpdate.Click
DoUpdating()
End Sub
End Class
Public Class frmIOMain
Private myFrmUpdateDueDates As frmUpdateDueDates
Private Sub IOMain_Load(sender As Object, e As System.EventArgs) Handles Me.Load
myFrmUpdateDueDates = New FrmUpdateDueDates()
myFrmUpdateDueDates.Show()
'myFrmUpdateDueDates.cmdUpdate_Click(Nothing, Nothing)
myFrmUpdateDueDates.DoUpdating()
End Sub
End Class
I read various posts, and made a practice project, but it does not works.
The form have a button and a text box with a default text 'Updated 0 times'. On button click starts the timer and each time update the text with the number of times the text was updated.
The exception of cross thread calls is not thrown, but when calling the text box, its .Text = "", the text is updated but not the text box on the form. And InvokeRequired is always false.
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'Here the textBox.Text = "Updated 0 times."
Dim checking_text As String = Me.TextBox1.Text
TimerTest.StartTimer()
End Sub
Delegate Sub UpdateTextInvoke(ByVal new_text As String)
Public Sub UpdateText(ByVal new_text As String)
'Here the textBox.Text = ""
Dim txtB As TextBox = Me.TextBox1
'InvokeRequired always = False.
If txtB.InvokeRequired Then
Dim invk As New UpdateTextInvoke(AddressOf UpdateText)
txtB.Invoke(invk, New Object() {new_text})
Else
'The value of this text box is updated, but the text on the form TextBox1 never changes
txtB.Text = new_text
End If
End Sub
End Class
Public Class TimerTest
Private Shared tmr As New System.Timers.Timer
Private Shared counter As Integer
Public Shared Sub StartTimer()
tmr.Interval = 5000
AddHandler tmr.Elapsed, AddressOf UdpateText
tmr.Enabled = True
End Sub
Public Shared Sub UdpateText(ByVal sender As Object, ByVal e As System.EventArgs)
counter += 1
Form1.UpdateText(String.Format("Updated {0} time(s).", counter))
End Sub
End Class
SOLVED
In the Class TimerTest added this code 'Private Shared myform As Form1 = Form1'
then changed 'Form1.UpdateText' To 'myform.UpdateText'
As indicated in the comments, you are using the default form instance feature of VB.Net. You could pass an instance of the form to the TimerTest class, and replace the reference to Form1 with the instance.
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim checking_text As String = Me.TextBox1.Text
TimerTest.StartTimer(Me)
End Sub
Public Sub UpdateText(new_text As String)
If TextBox1.InvokeRequired Then
Dim invk As New Action(Of String)(AddressOf UpdateText)
TextBox1.Invoke(invk, {new_text})
Else
TextBox1.Text = new_text
End If
End Sub
End Class
Public Class TimerTest
Private Shared tmr As New System.Timers.Timer()
Private Shared counter As Integer
Private Shared instance As Form1
Public Shared Sub StartTimer(formInstance As Form1)
instance = formInstance
tmr.Interval = 5000
AddHandler tmr.Elapsed, AddressOf UdpateText
tmr.Enabled = True
End Sub
Public Shared Sub UdpateText(ByVal sender As Object, ByVal e As System.EventArgs)
counter += 1
instance.UpdateText(String.Format("Updated {0} time(s).", counter))
End Sub
End Class
What im trying to do is start a thread of a Sub which is inside a class , that will change form1's label1.text . Apparently this code doesnt work .
Public Class Form1
Public Class test
Public Sub doit()
Form1.chan("hello")
End Sub
End Class
Delegate Sub changeit(ByVal test As String)
Public Sub chan(ByVal test As String)
If Me.Label1.InvokeRequired Then
Dim d As New changeit(AddressOf chan)
Me.Invoke(d, {test})
Else
Me.Label1.Text = test
Label1.Refresh()
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim a As New test
Dim thread As New Threading.Thread(AddressOf a.doit)
thread.Start()
End Sub
End Class
Hi I get the error above when I ran this code. When I try to run a VBNet program that has 3 forms.
I'm just trying to pass list Items from one form to another, but I get an error before the program compiles.
Public Class frmCart
Dim frmComic As New comicBooks
Dim frmAudio As New audioBooks
Public decSubTotal As Decimal
Private Sub ShowToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ShowToolStripMenuItem.Click
frmComic.ShowDialog()
End Sub
Private Sub ShowDialogToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ShowDialogToolStripMenuItem.Click
frmAudio.ShowDialog()
End Sub
End Class
Now the frmComic is
Public Class comicBooks
Dim frmCartForm As New frmCart
Public decPrice1 As Decimal = 20.95D
Public decPrice2 As Decimal = 10.50D
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Select Case lstComicBooks.SelectedItem
Case "Comic #1 (Print)"
frmCart.lstProductsSelected.Items.Add("Comic #1")
frmCart.decSubTotal += decPrice1
Case "The History of Scotland (Print)"
frmCart.lstProductsSelected.Items.Add("Comic #2")
frmCart.decSubTotal += decPrice2
Case Else
MessageBox.Show("Please select a Comic")
End Select
End Sub
End Class
I don't know why it's recursive if I call the Dialog only once.
Thanks
To avoid recursion, you should pass the current instance of frmCart into the comicBooks class in the constructor. Something like this:
Public Class frmCart
Dim frmComic As New comicBooks(Me) '<--- Pass current form into constructor
End Class
Public Class comicBooks
Dim frmCartForm As frmCart '<--- variable to hold passed in form instance
Public Sub New(cartForm As frmCart) '<--- Constructor to take instance of form
Me.frmCartForm = cartForm '<--- Assign passed in reference to our variable
End Sub
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
'Use frmCartForm here
End Sub
End Class
Class comicBooks instantiates a new frmCart.
frmCart instantiates a new comicBooks
Go back to 1
Remove the frmCartForm declaration in comicBooks
I've managed to get the data I want in a thread, however I'm having trouble getting my head around passing the data back into my main thread (GUI).
I'm grabbing data from a network stream in a thread, then need to pass it to my main thread in order to pass to other classes etc.
I've seen it mentioned to use backgroundworker for this, but as I'm expecting it to gather data periodically and never stop, I thought a separate thread for this would be best, but I'm very new to multithreading.
If threading is the correct way to go, how can I pass data from it back to my main thread in order to use this for other stuff? I've seen delegates and events mentioned a lot but can't see how I'd pass data with these?
Thanks
Please study this example, and let me know if it fits your requirements:
Controls required: lstItems (ListBox), btnStart (Button), btnStop (Button), Timer1 (Timer).
Form1 code:
Public Class Form1
Dim p_oStringProducer As StringProducer
Private Sub btnGo_Click(sender As Object, e As EventArgs) Handles btnGo.Click
p_oStringProducer = New StringProducer
p_oStringProducer.Start()
Timer1.Enabled = True
End Sub
Private Sub btnStop_Click(sender As Object, e As EventArgs) _
Handles btnStop.Click
Timer1.Enabled = False
p_oStringProducer.Stop()
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Dim asQueue As Concurrent.ConcurrentQueue(Of String) =
p_oStringProducer.MessageQueue
While asQueue.Count > 0
Dim sItem As String = Nothing
asQueue.TryDequeue(sItem)
lstItems.Items.Add(sItem)
End While
End Sub
End Class
StringProducer code:
Imports System.Threading.Tasks
Public Class StringProducer
Private p_fKeepRunning As Boolean
Private p_oTask As task
Private p_aMessageQueue As Concurrent.ConcurrentQueue(Of String)
Private p_iNextMessageId As Integer
Public ReadOnly Property MessageQueue As _
Concurrent.ConcurrentQueue(Of String)
Get
Return p_aMessageQueue
End Get
End Property
Sub New()
p_oTask = New Task(AddressOf TaskBody)
p_aMessageQueue = New Concurrent.ConcurrentQueue(Of String)
p_iNextMessageId = 0
End Sub
Public Sub Start()
p_fKeepRunning = True
p_oTask.Start()
End Sub
Public Sub [Stop]()
p_fKeepRunning = False
End Sub
Private Sub TaskBody()
While p_fKeepRunning
Threading.Thread.Sleep(2000)
p_aMessageQueue.Enqueue("Message #" & p_iNextMessageId)
p_iNextMessageId += 1
End While
End Sub
Protected Overrides Sub Finalize()
MyBase.Finalize()
Me.Stop()
End Sub
End Class
This was not extensively tested, but it should give you a head start.