VB .net Infinite Loop/Interrupt Driven - vb.net

I'm pretty new to VB .net still and I'm attempting to write a program that constantly watches information pulled from a PLC and updates when it changes.
I've worked some with microcontrollers and I know making an infinite loop works well. What I'm running into with my VB .net code is when it loops, the form basically freezes up and the label never updates. I attempted using the code below.
Do While True
*Code*
Loop
So, I guess my first question is, what is the best way to go about having a continuous program to update data. It seems an infinite loop is not the answer.
My second question is, like microcontrollers, is it possible to have VB .net be an interrupt driven program instead of an event driven. My program is always running, updating the data as it comes in, but if a button is pressed it can essentialy break out of the loop. Or what I have in mind, temporarly leave the loop to perform another function then continue back into the loop.
I've looked at the System.Timers namespace, and am not 100% clear on how they work. It seems like it is potential answer to my problem. If I have a timer that does the code every one second, this one second occures as long as the form is running correct? Assuming the previous statement is correct, if the code is running from the 1 second tick, and a button is pushed while that code is running, will the button be ignored, or will the event happen after the code has finished.
Anything to help me learn will be greatly appeciated!

You can use the
Application.DoEvents()
-method provided by the .NET framework, it essentially updates your form to apply all the changes that happened in the meantime.

Related

Update UI with progress during UI-intensive loop

I've got a long-running loop which involves a fair amount of UI functions. This loop therefore must be run on the main thread. However, I also want to display progress of this task, so this must also run on the main thread as displaying the current progress would involve updating the UI. I am really struggling to find a way of allowing the UI to update with current progress on the main thread when the main loop is also running on the main thread. What happens is that the UI is frozen during the loop and then updates to show that the process is finished when it's done.
This is not for a production app, it's for a personal project that will never be release. So it is of no concern that the UI is frozen from a UX perspective. If the solution involves putting the processing in the background then this refactoring is fine, but I'm not sure how to do it when a lot of the heavy lifting during this loop involves UI stuff too.
Isn't it funny how you sometimes come up with a solution just after posting the question?! The key seemed to be rather than using a for loop for the processing, instead putting the processing function inside a separate method and repeatedly calling it, passing the array of objects to process to it. Doing this, you can call the function using [self performSelector:withObject:afterDelay:]. Even if you provide a value of zero for the delay, it causes the method to be called on the next run loop. This means you can update the UI, process the next item, and repeat this process until the array of items is empty. Here's my completed solution. If anybody knows a better way I'd still love to hear it, but for now this is at least working!
Edit - I packaged this solution up into a class of its own to make it easier to manage, and put it on my Github. Maybe it will help somebody else out :)
Edit 2 - made the processing class more flexible by making it run loops instead of iterating through arrays. You can of course use it to iterate through an array yourself, as per the example in the readme. But if you're not working with an array, you can just run the loop runCount times and do whatever you need to do in the processingBlock.
https://github.com/mashers/BackgroundLoopProcessor

Excel freezes during execution

When I execute my code (which takes 3-4min. to execute) in Excel, and I click on something in excel or in my userform, it freezes, gets white, almost crashes... When the execution is ready everything is fine again.
Of course it is normal that I can't work in excel during execution, but how can I avoid the "crashing" of excel?
Do you have a Loop in the code?
If so, add the following line just after you initialize the loop and it should help with your problem!
DoEvents
The best way to prevent these kinds of issues is to benchmark your code to determine what is taking so long. If your code is taking over 3 minutes to run, you almost certainly have room for optimization.
Here are the steps you need to take:
Set multiple breakpoints within the code that is executing.
Time how long it takes to get from one breakpoint to the next.
Once you've identified the culprit(s), refactor.
If you aren't able to improve performance, post the inefficient code and ask for help.
A notorious slow-performing anti-pattern to look out for is selecting things during a loop.
What you need to do is create a custom UserForm that will overlay the Excel UI, like a Progress Bar. You'll also want to look into ways to force your form to stay ontop, much like a modal form. You can't use modal form's because they cease execution.
After you make sure there are no infinite loops making excel unresponsive try optimizing your code.
I found this a very interesting read on vba-excel code optimization and some of the practices actually had an impact on a big and time consuming module I wrote. Hope it helps.

VB.NET Synchronization confusion

VB.NET, .NET 4
Hello all,
I have an application that controls an industrial system. It has a GUI which, once a process is started, principally displays the states of various attached devices. It basically works like this:
A System.Timers.Timer object is always running. At each Elapsed event, it polls the devices for their current values and invokes controls on the GUI, updating them with the new values.
A start button is clicked, a process time Stopwatch object is created and started (Labels on the GUI are now invoked and updated on the System.Timers.Timer's Elapsed event, in addition to the other work that is taken care of on this event)
A new thread is created which runs a Process() subroutine
Some Stopwatch objects are created and started (these Stopwatches are periodically restarted during the process via their Restart() method.
Some logic is executed on the new Stopwatchs' Elapsedmilliseconds properties to determine when to do things like write new setpoints to the devices, update the data log, etc...
Here's my problem: The program occasionally freezes. My ignorant efforts at tracking down the problem have led me to suspect that read/writes to the subset of devices that are RS-232 controlled are the culprits most of the time. However, I occasionally see other strange things upon program freeze, e.g., one of the time Labels whose Text property is determined by a Stopwatch's Elapsedmilliseconds property sometimes will show an impossible value (e.g., -50 hours or something).
For the RS-232 problems, I suspect something like a read event is being executed at the same time as a write event and this causes a freeze(?). I tried to prevent this by making sure that all communication with an RS-232 device is funneled through a Transmit() subroutine which has the following attribute:
Which, as far as my ignorance permits me to understand, should force one Transmit() execution to finish completely before another one can start. Perhaps another risk is the code getting blocked here if one Transmit() never finishes?
Regarding the Stopwatch trouble, I speculate that the problem is that the Timer is trying to update a GUI Label at the same time that the Stopwatch's Restart() method is being executed. I'm unsure if this could cause a problem. All I know is that this problem has only occurred at a point in the process when a Restart() call would be made.
I am wondering if I could use a SyncLock or something to lock a Stopwatch while the Label is being updated (or, conversely, while its being restarted)? Or, perhaps I should stop the Timer, restart the Stopwatch, and then start the timer again, like so?:
Timer.Stop
Stopwatch.Restart
Timer.Start
My trepidation regarding how to proceed is due to my complete lack of understanding of how .NET synchronization objects actually work. I've tried slapping a few SyncLocks in various places, but I really have no idea if they're implemented correctly or not. I'm wondering if, having provided all this context, someone really smart might be able to tell me how I'm stupid and how to do this right. I would really appreciate any input. If it would be useful to provide some code snippets, I'd be happy to, I just worry that everything's so convoluted that it would just detract from what I'm hoping is a conceptual question.
Thanks in advance!
Brian
I would consider a shift to a task scheduling framework instead of relying on manual manipulation of timers if your working on anything SCADA related. A simple starting point would be something similar to the hardcodet.Scheduling classes and you can move to something like the beast that is Quartz. Most of these types of frameworks will provide you with a way to pause and resume scheduled actions.
If I'm working with Modbus, I normally keep a local cache of the register values and make changes to any value fire a change event. This has the benefit of allowing you to implement things like refreshing values manually without interfering with your process scheduling and checking for deadband when evaluating your polled response. This happened to be the side effect of implementing a polled protocol to a subset of the OPC DA interface.

How can I force a progress bar to update during a long-running operation in VB.NET?

I am running a test program for VB.NET, and it will simply crunch a million numbers in for loop. I've linked a variable implying the progress of the for loop with the progress bar, but it seems that when I run the program, the progress bar does not update itself. The bar itself has only value 0-100 as input (as stated in the document) and I've tested it without using the for loop, and it works.
I think this has to do with threads, but I am not sure how things work in VB.NET exactly yet. So I want to seek an advice from an expert first.
Any advice is appreciated.
Don't know if this still applies for .net (or if this is a VB6 question), but Application.DoEvents was generally the solution in VB6 days.
Try Application.DoEvents inside your loop that updates the progress bar.
long time ago but i think you need the
DoEvents
statement

Why does this program need MsgBox?

Long story short: I'm trying to write an app that'll dump IE's history to a text file. Because I am lazy, I went searching for a preexisting library and found this beautiful project to build from: http://www.freevbcode.com/ShowCode.asp?ID=6702. Only, I'm stuck...
I finally got the program to dump the history, but it only works if I put a MsgBox() on line 169 of Module1.vb. I've tried putting a Thread.Sleep() there, but that doesn't work. There has to be a message box there, or only today's history gets listed.
My guess, since this is talking to wininet.dll, is this is a concurrency thing. Thread.Sleep() (for a For...Next loop) stops the program from listening; nothing there makes it exit the loop before values are assigned, but a MsgBox() is just right. Is there something besides MsgBox() that will have the same effect? I'd like to not have to hit OK thirty times to make the program work.
Here's my branch/version/derived work: http://profnano.org/andy/misc/img/HistList.zip; it's a VS.NET2003 project.
MsgBox() pumps a message loop. That can get all kind of code unstuck. Windows get a chance to paint themselves. COM deadlocks due the main thread getting stuck in a loop are solved, always an issue when IE is involved. Calling DoEvents() is the very imperfect alternative to MsgBox().