I have a winforms program written in visual Studio, coded in visual basic.
The main part of the program is a while loop that sends out serial commands, writes data to sql, does basic arithmetic, and updates controls on my form. I have this while loop in a background workers do work sub so that the controls can be updated from the background worker sub, while it is still running. After awhile of running, my form will freeze up, while halfway through updating several text boxes. However, the background worker continues to run, the sql data still gets written, and most curiously clicking a button on the form does what it is supposed to, even though we can't see that the button was pressed.
I can't think of anything that would cause behavior like this, where visually the form is frozen, but all the controls still respond.
It freezes because the UI thread is busy with the loop. It seems that you didn't implement the background worker properly and it is still attached to the UI thread.
You can add DoEvents somewhere inside your loop, which gives the UI thread some time to handle UI events. But this is just a Band-Aid fix because I don't know your code. The ideal way is to fix your background worker and its relationship with the UI thread.
Related
I am currently working on a LabVIEW project and have found myself stuck on how to make a while loop exit when I press the abort (stop) button. For a simple while loop I understand how to do this - but the problem is that this while loop is nested inside of an event structure and I'm guessing that the button cannot be pressed while the loop is executing. Attached here is a picture of part of my code (that contains this specific event case which is causing me problems): To spend a little more time explaining what the problem is - I think the code is doing what I want it to do (namely output a set of commands in a repeated cycle with a wait timer) but I cannot stop the code mid cycle (pressing the abort button with my mouse does nothing - as in the button doesn't show it being pressed and the indicator shows no change, I also can't use any other functionality of my program during the cycle which I'm assuming is related). And I do not want to stop the LabVIEW program from running entirely - just the code inside the while loop pictured above. This is what the front panel is configured too for completeness:
Essentially what I want to happen is the while loop to execute when I press DWG and in the middle of the cycle be able to abort it. Sorry if my code seems a little messy. Additionally, I've tried the same code with a for loop originally (via a conditional terminal so it could stop early) and that didn't work either. Thanks for any help I appreciate it!
Your problem is that inside the event structure, by default the UI is frozen so no UI actions (keyboard/mouse/etc) are processed until you exit that frame.
Option 1. You can right click the Event Structure and select "Edit events handled by this case" dialog and then uncheck the "Lock panel" checkbox -- that will allow the UI to be live while you are in that frame. I do not recommend this solution generally unless you have an extremely simple user interface because it leads to the user being able to change controls without the events behind those controls being processed (not a good UI experience for users). But if the UI is simple enough, that works.
Option 2. You can create a user event that is the code you want inside your While Loop. When the Deg Wait Go button is pressed, use the "Generate User Event" node to trigger that event. Do the same thing in the user event case so that the event re-triggers itself if and only if the Abort button has not been pressed.
Option 3. Create a separate loop OUTSIDE your UI loop that does your processing with some sort of command queue running between the UI loop and that other loop. The other loop moves into various states at the request of the UI loop... it's the one that does nothing until it receives a "go" message and then keeps looping until it receives a "stop" message. You can Google "queued message handler" for extensive details of this solution. This is the most common solution for complex UI requirements, especially useful for separating concerns of the UI code from the execution code.
How do I track what events are currently 'Active' or currently being handled while stepping through the code.
The Issue
While I was debugging code (stepping through it) within a rather large application, all of a sudden I found that the code that was being run was running through code in functions that had nothing to do with the code I was troubleshooting. It took me a considerable amount of time to figure out why I found myself stepping through code in functions that were way outside the code I was debugging.
Turns out, at the start of the application, handlers are added to certain controls as well as timer controls. The timer control triggers an event every 5 minutes or so. There were other events being triggered when certain actions were taken, however I had no idea what was causing the debugger to enter into certain functions due to the fact that there was no indication or 'prompt' telling me an Event was Triggered and that was why I was now stepping into other functions.
How do I become aware of what is happening when events are triggered in the manner I mentioned above?
Note
This is not a question about how to add handlers or remove handlers in code.
So basically timers are still running in the same thread as the main logic. every time a function/Event is done and the Window steps into the waiting part in which unser input is read and events are started, timers will trigger. they will not run while other events are busy. If you use Background Worker or start second threads. they will run in between you current steps and the visual studio will jump from one to another. there is a thread window to keep track of all active threads but this only gives a clue. sometimes its still annoying to jump from one to another function. My advice is to use a debugger-hidden attribute on those functions that keep on bothering you.
How to find the Thread window:
How can I view Threads window in Visual studio?
How to use Debugger Hidden:
https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.debuggerhiddenattribute?redirectedfrom=MSDN&view=netframework-4.7.2
and
https://social.msdn.microsoft.com/Forums/vstudio/en-US/cf20736c-cbfb-4919-b495-ea9a9235f9e5/debuggerhiddenattribute-example?forum=csharpgeneral
I wrote a VB.NET Windows Forms app that requests a string from an out-of-process COM object every time the activate event fires. My form has two tabs, so I need to programmatically flip to the correct tab every time my window gains focus. Works fine, until...
By chance, someone ran a vbscript (yes, script, not exe) that contains:
Set shell = CreateObject("WScript.Shell")
shell.AppActivate("Window Title That Matches My App")
This script consistently crashes my app. Usually so badly that the Exception dialog usually can't paint itself. I have to kill it from task manager. Sometimes the Exception is readable. (I also confirmed the exception by attaching to the running exe with Visual Studio). It's: "System.Runtime.InteropServices.COMException (0x8001010D): An outgoing call cannot be made since the application is dispatching an input-synchronous call."
What's really messing with my mind is that my app has multiple instance detection using a mutex, and if an existing instance is running, my own code (compiled) uses VB.NET's own AppActivate keyword, and this does NOT crash my app. It activates the running instance and exits the redundant instance as expected.
The problem seems solely to be triggered by cscript/wscript's AppActivate. I wrote a 3-liner .vbs to confirm this. It's repeatable.
Is there a way to trap or avoid this in my compiled app?
It's not clear to me WHY this approach actually fixes the problem, but it DOES work:
Add a timer to the form.
Move all the _Activated code to the timer's _Tick event.
Make the _Activated event start the timer.
Make the _Tick event stop the timer then perform the COM stuff.
I am running a lengthly task in an Action and I would like to have a display of where I am at. For that I created a Text Field and I tried it with setStringValue:
[textField setStingValue: [NSSting stringWithFormat:#"%ld",currentValue]]
The code works but unfortunately it is not updating the NSTextField after every iteration but rather when the whole Action is done.
What am I doing wrong?
This is because applications with the Cocoa framework use an event loop to perform operations, and events occur in a completely serial fashion.
An event is basically any kind of action that the framework designer could not predict or found convenient to have run in a delayed manner. Since you can't predict when clicks will be performed, they need to be considered events; and for efficiency reasons (since you don't want to repaint a component multiple times if you don't need to), the repaint actions are events too.
Your action runs in response to a user event (for instance, a click on a button is an event) and therefore blocks all other events waiting in the queue until it's complete. However, components are repainted in response to a different, framework-triggered event, and as such the text field must wait until your action completes to repaint itself. This is why you cannot visually change the value of a text field from inside an action.
In order to notify your user of the progress of your task, you'll need to run it on a different thread. There's a lot to say about threads, so you should probably read some about them. I'm also sure that there are plenty of examples of how to run a long action in a background thread and update the UI accordingly for Cocoa all over the Internet.
When you click on a UI component, and it enters the Action block, the code is running on the main thread, the same thread that is painting the UI. If you run a long running operation in that block, it isn't going to paint until you are done because it is busy doing whatever you have it doing - you have hijacked the paint thread.
As said elsewhere, you need to spawn another thread, and then have the new thread perform the long running operation, and occasionally send messages to have the UI be updated by the main thread.
As a next step, go read the Apple documentation on NSThread, specifically:
+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
Be aware that threading is a non-trivial domain area, and be ready for some wierd behavior if you aren't careful.
I'm having a weird issue with form painting in the Compact Framework. I have a login dialog that is basically a small form that is opened on top of another using ShowDialog. When a card is swiped, the login dialog is supposed to close, then some login tasks are performed and then the form behind it should be activated. The problem is that the form behind the login dialog is not being refreshed and so the login dialog will not be removed until after the form behind is refreshed by some user action. This is probably due to the heavy processing that goes on in the login tasks part, but I've not found a way to solve this.
Basically, I want a way to force the application to close the dialog and paint everything again, before performing the heavy login tasks. I've tried numerous refresh methods without any luck:
Form loginDialog = new Form();
DialogResult result = loginDialog.ShowDialog();
loginDialog.Dispose();
//I've tried everything at this point to get the form to refresh before performing
//login tasks
this.Refresh();
this.Invalidate();
Application.DoEvents();
PerformHeavyLoginTasks();
Does anyone know what could be going wrong? Thanks
Ok I figured this out. The problem was with a custom control on the background form that manually paints itself using rectangles and such. I think this is a compact framework bug since I called Refresh and Invalidate on that control as well and it should've repainted. I had to create a method that would call the control's OnPaint override directly since Invalidate and Refreshed were pretty much ignored.
The issue, I believe, is that you're not fully understanding what's going on system-wise here.
When your fore window (the Dialog) is dismissed, the background window (the Form) is given focu and tol to repaint the clipping region where the dialog was. This happens via a PostMessage call, which sends a Windows Message that has to be popped, translated and dispatched down in the bowels of the Application.Run call.
This is, by design, a fairly slow process as the UI should not be preempting things that are important.
If you are doing heavy processing immediately after that PostMessage happens, the processing of those windows messages can often be slowed, ending up with the UI appearing "locked" or drawing really slowly. This is exacerbated if the processing you're doing is on the same thread as the UI.
Why are your efforst not making things better?
Calling Refresh simply sends another message. That message now gets in line for processing, so it would actually make things worse.
Calling Invalidate does pretty much the same this as Refresh, just asynchronously. Again, it makes things worse.
DoEvents tells the message pump to pop, translate and dispatch a message. That dispatch still has to be processed on the UI thread, so noting is going to happen until the thread has time to do the work (i.e. after your processing)
So how do we "fix" this?
The first step is often to put the processing on a separate thread to allow the scheduler to round-robin tasks between the UI and processing threads, up to the default quantum. Thgis means that the processing can only starve the UI for a maximum of 100ms before some sort of drawing is allowed to occur (assuming equal thread priority).
new Thread(PerformHeavyLoginTasks)
{
IsBackground = true
}.Start();
You can go a step further and give the UI a "jump start" on the processing (of 10ms in this example):
new Thread(new ThreadStart(delegate
{
Thread.Sleep(10);
PerformHeavyLoginTasks();
}))
{
IsBackground = true
}.Start();
Of course this may mean you need to now handle the next "display" asynchrously if the UI you want to display is dependent on the processing result. There are plenty of online resources for async patterns, so I won't beat that dead horse here.