VB.net Messages Pumped to Label - vb.net

I basically want to implement a Label and have it constantly showing information to the user. I want to be able to do something like this:
someMethod():
printMessage("Starting program")
doWork() //possibly does some calls to printMessage()
printMessage("Finished program")
end
printMessage(string message)
mylabel.Text += message
end
And have the label on a Windows Form constantly be showing that output. That is, instead of the user having to wait until someMethod() is finished and having all the info suddenly dumped on to the label, I want it to be printed to the label as the information comes out.
I tried looking at threading to solve this problem, and I have it working using code something like:
someMethod():
Dim t As New Thread(AddressOf printMessage)
t.Start("Starting program")
doWork()
printMessage("Finished program")
end
(And there is a delegate for printMessage and inside I check the InvokedRequired property of mylabel) But with this, I keep getting all the information just suddenly dumped on to the label, and the order is no longer preserved. I may get output like:
"some other data from doWork()"
"Finished program"
"Starting program"
So any ideas how I can accomplish this?
Thanks.

You might want to consider using a BackgroundWorker. It will make it easy for you to have the work done on a separate thread and still report progress back to the UI thread.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
And have the rest of the app remain responsive.
The BackGroundWorker has a DoWork event where you could put code that looked (roughly) like this:
BGW.ReportProgress(0, "Starting Task1")
DoTask1()
BGW.ReportProgress(0, "Completed Task1")
BGW.ReportProgress(0, "Starting Task2")
DoTask2()
BGW.ReportProgress(0, "Completed Task2")
You'd also handle the ProgressChanged event which will fire (on the thread that started the worker) to update the label.

A call to Application.DoEvents() may be beneficial, as it forces the window to update.
Try placing it right after each of your printMessage calls.

Related

In VB.NET use a textbox as a log for which if statement it is beeing proccesed inside a sub

Hi i have a Sub that has multiple if statements in it.
Each if statement has a large loop that searches for specific files and text inside files.
I tried various ways to use a text box in order to get the information which if is currently proccessing at the time and i see that for some reason the ui is not refreshed until the sub finishes and so i see everytime in the textbox the last proceesed if message.
What do you think is the best way to handle it?
I hope that this has nothing to do with threads because threads are something that i am not familiar with !
I think using Application.DoEvents() is an easy choice. But I don't know if that would be the desired behavior.
If the use of Application.DoEvents() fails, another thread should handle it.
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.application.doevents?view=netframework-3.5
I use this:
Public Sub logWithCrLf(tx As TextBox, s As String)
tx.AppendText(s & vbCrLf)
tx.Select(tx.TextLength - 1, 0)
tx.ScrollToCaret()
tx.Refresh()
End Sub
I see that it scrolls a bit smoother using tx.AppendText(s) than tx.Text &= s, which scrolls up to 0 then down to caret again.
(I write this as an answer to contribute with the tx.AppendText() recommendation)

Async event handler - flycapture from PointGrey

I am using Point Grey's FlyCapture API to drive some cameras.
In a public class, I implemented all the starting and initializing code ; in the following _cam refers to a ManagedGigECamera.
Because I have 16 cameras, I want the code to be as fast as possible, so I wanted to use tasks.
Here is the code I use:
_cam.StartCapture(AddressOf OnImageGrabbed)
.../...
Public Sub OnImageGrabbed(ByVal raw_image As ManagedImage)
Dim t As Task = Task.Run(Sub()
'save image to disk or whatever
End Sub)
t.Wait()
End Sub
The above gives -sort of- satisfaction. By viewing image timestamps, I can see that some images are saved seconds after they are grabbed, and even some images are skipped altogether...
I wanted to make sure each call to OnImageGrabbed would start a new task, and tried the following, but it crashes right away with 'object not set to an instance of an object' (can't really debug, the code is running on a remote machine)
_cam.StartCapture(AddressOf OnImageGrabbed)
.../...
Public Async Sub OnImageGrabbed(ByVal raw_image As ManagedImage)
Await Task.Run(Sub()
'save image to disk or whatever
End Sub)
End Sub
All in all, my questions are:
how can I run an event handler asynchronously ?
why, using the first code, do I get (what appears to be) random delays between each call
to OnImageGrabbed ? I mean the differences in time between image timestamps is never the same, and tend to increase on the long run (first few images are almost synchronized, but after 1 minute or so, each image is separated by more and more time). Memory leak ? GC ?
Thanks in advance for any hint !
EDIT:
In the end I changed the way the system works: I fire a software trigger on each camera using a timer, and each trigger is fired 'in parallel':
Parallel.ForEach(Of ListOfCameras)(SingleCamera,
Sub(aCamera, loopstate, num)
aCamera.FireTrigger()
End Sub)
Starting a task and then immediately blocking on it (via Wait) nets you nothing. You may as well just run the saving-image code directly.
The second example is actually asynchronous. You're probably getting an exception because the ManagedImage argument or one of its child objects is being disposed. Remember that the code raising the event has no idea that your code is asynchronous; it's up to you to copy out what you need from the event arguments if you're going to use it asynchronously.

What Would Cause A Form To Freeze Upon Executing Code

I'm trying to figure why my form freezes up when executing some code. I also can't minimize or move the form. Is it because of the WaitForExit being used in the process?
The below code is tied to a button click.
If Checkbox1.checked = True Then
Call Test()
End If
If Checkbox2.checked = True Then
Goto NextStep
Else
Goto StopProcessing
End If
Here is the test sub I'm calling. Calls an exe with an optional argument.
Using psinfo As New Process
psinfo.StartInfo.FileName = "C:\Temp\Test.exe "
psinfo.StartInfo.Arguments = Arg1
psinfo.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
psinfo.Start()
psinfo.WaitForExit()
End Using
The WaitForExit was added (so I thought) to not process the next statement (next statement being the If statement for Checkbox2) until the process was complete. Is this not the case?
The WaitForExit was added (so I thought) to not process the next statement (next statement being the If statement for Checkbox2) until the process was complete.
When you call WaitForExit, it will block until the process (Test.exe) completes.
Since you're running this on the user interface thread, it will cause your form to "freeze" until the process completes fully.
If you need this to not occur, you would need to wait on a background thread. You could, potentially, move this code into a BackgroundWorker and use it to synchronize with your main window - but you will need to handle "waiting" for the process to finish in a different manner (ie: disable your UI up front, run the process, re-enable when complete).
Note that, with the Process class, another alternative would be to add EnableRaisingEvents on the process, then adding a handler to Process.Exited. This will let you not WaitForExit(), but instead get notified via an event when the process completes.

How to CORRECTLY implement a multithreaded progressbar during a LINQ query?

Okay so here's the thing:
I have a linq query which loads approx. 1000 lines into a variable, during that process I want to display a progressbar, not necessarily stating the percentage, can be marquee style, doesnt matter.
This progressbar is on a modal form to precent the user from interacting with the app for the time the query's running.
Now here's my code:
Private Sub LoadBar()
Try
Dim load As New frmLoadbar
load.Text = "Loading bunch of data..."
load.ShowDialog()
Catch e As Threading.ThreadAbortException
Threading.Thread.ResetAbort()
End Try
End Sub
In another sub:
Dim myThreadDelegate As New Threading.ThreadStart(AddressOf LoadBar)
Dim th As New Threading.Thread(myThreadDelegate)
th.Name = "TimeConsuming"
th.Start()
Dim XY = db.Table.GetEnumerator
While XY.MoveNext
Dim item As New ListViewItem
item.Text = XY.Current.Name
item.Tag = XY.Current
ListBox1.Items.Add(item)
End While
Autos.Dispose()
Try
th.Abort()
Catch ex As Exception //here's where i 'swallow the re-thrown exception
End Try
Not thats one of the ugliest code i've ever written.It works i just dont want that rethrown exception.
Some explanation:
I want the modal form to close after the query is done.
For that reason I 'abort' the thread running the form.
Since aborting a thread throws a double-exception i have to 'swallow'
that exception.
Now i know i could implement this like the following:
Coding a loop into the form holding the progressbar, which checks
periodically for a boolean's value, and if its true the form could
close itself.
From the other form - on the worker thread - i could change that
booleans value to true after the query's finished.
But here comes my question:
Whats the best way to implement this?
I know it can be done with a background worker, which has been
specifically invented for this reason, but can i use the background
worker as the thread to show the progressbar?
If not (and i have to run the query on the background worker and
showing the modal form from my original form), would that mean that
the query would "work in the background"?
Would that mean that the query would be slower?
I've looked into other tutorials, but for one reason or another, either i wasnt able to copy it (due to complexity) or I wasn't convinced that it was better than this.
Thank you for your time you took to answer.
You could show the modal form and then run a BackgroundWorker from that form. The progress and completed events would be on the UI thread so you can update a progress bar while it is running and close the form in the completed event handler.
Okay, so for future reference, if someone needs clear help with code samples, Microsoft has it (thats a first..)
You can download it here:
Multithreading
Assuming Windows Forms, you do this with a BackgroundWorker component.

i written a winforms application in VB .NET in visual studio 2010

I have to run a thread create in the code.
In the form1 i have a button that run the new separate thread for elaborate some data, so i need it for not freeze the form.
I have inizialized thread:
dim th as thread = new thread (addressof elaborate)
And at the button.click event:
th.isbackground= true
th.start()
Now, at the form load i have iconized my program, but when i start new thread the tray icon is duplicated from it.
I want to resolve that when start new thread it's not show new notifyicon.
Any ideas?
(i don't have found anything online, only Multiple notification icons appear when using multithreading)
Create a class called Elab
inside that class, put a sub called work
Add a timer to your form that is disabled
with a tickcount of say 1000
Declare this in your form class:
Dim El as Elab
inside Form_Load() put:
El = New Elab()
Under your button, put this:
Dim gThread as new System.Threading.Thread(Address of El.Work)
Timer1.Enabled = True
Inside Elab declare a variable called Result:
Public Result as boolean
When elab has finished whatever it is doing, set result as true, and store the results in public variables you can access later.
Inside the timer:
If El.Result = True then
'Get results, deal with data
end if
This isn't written particularly well, and isn't a working example, but is to mearly point you in the right direction, by giving a thread an address of a sub inside a class, you can then access the same class from other threads, which means your form doesn't freeze, and you're not creating a new instance of your form, you are just accessing an existing classes sub routine; just make sure to give yourself a way to get the results (in this example i suggested a timer, but a "get result" button would do the same job) once the thread has completed.
Remeber:
If you need Elab to finish before a particular part of code can continue (for example, elab might add two numbers, and you need the result to continue) you can start the thread and do this:
Do until El.Result = True
Application.DoEvents()
System.Threading.Thread.Sleep(1)
Loop
gThread.Join()
Hope this helps a little.
So the answer to your question is; don't put your sub inside a form, instead put it in a class that you can create an instance of.