How to Pause C# code execution without blocking main thread? - c#

OK so we have a program where we want to animate the controls on a WinForm and then then resume subsequent operations of the remaining block of code. Here is the sample code.
The function is on the WinForm, which is running on main thread presumably
Private void DoThisWork();
{
do some work here
animateControls()
//<NEED TO PAUSE HERE WHILE THE GUI ANIMATES AND UPDATES DISPLAYING THE ANIMATION OF THE CONTROL>
//Tried Option 1: thread.sleep. When we do this the main thread blocks and the animation is //not seen. The control is directly painted at x1,y1 and thats it, the intermediate rendering is not seen
// Tried Option 2: Application.DoEvents. This works very well except that the CPU maxes out and the animation then appears very jittery
continue doing remaining work // must execute only after animateControls() completes the animation part.
}
Now, animateControls() is simply a function that is on a timer and moves a control from point (x,y) to (x1,y1) and this takes about 3 seconds.
SuspendLayout and ResumeLayout dont force GUI update because thread.sleep caused the main thread to block so everything is virtually at a standstill.
Using a different thread to animate the GUI does not seem to help because I still need for the entire animation to complete.
Also, I cannot add anything in the animation code because it is called from multiple functions and therefore is used as a common function.

Your are going down the wrong path. Put your work to do on a seperate thread and let your UI Thread do your animation till the work thread is finished.
The BackgroundWorker class might come in handy. http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

Related

Helix Viewport continues zooming while paused at a breakpoint

I am running a Helix viewport and am catching a mousewheeled event with previewmousewheel to run a method. When debugging some changes I made to my methods I found out that when I set a breakpoint (anywhere between the catching of the mousewheeledevent and the subsequent applying of the zoom in the viewport) the amount of zoom from one detent of the mousewheel will increase continuously in proportion to the amount of time the program has been paused (basically the amount of time elapsed from the mousewheeledevent and the applying of the delta to the viewport). This makes debugging my changes the way I normally do seem not possible, though of course I can work around this.
The real problem is that now I realize that the zoom is completely erratic in this way, because some operations take longer than others between the event and the setting of the viewport, depending on what I'm doing.
This seems like a completely haphazard thing to have going on when I'm trying to make changes to a camera and completely control the camera behavior based on details specific to my program.
Is there any way to disable this from happening or mitigate it almost entirely?
The following code is a snippet from my program that seems to be the main driver of the issue, but I'm not sure I can just remove this method of keeping time in the program, because we definitely need an asynchronous timekeeper as far as I know.
private async Task DoWorkAsyncInfiniteLoop()
{
while (true)
{
if (Run)
{
Time.timeElapsed += Time.runSpeed;
Time.simTime += Time.runSpeed;
updateAll();
}
// don't run again for at least 200 milliseconds
await Task.Delay(Time.interval);
}
}
perhaps there is some lines I can add that will basically allow me to apply the zoom to the viewport without waiting for the await Task.Delay(Time.interval) line to run?
I must admit I'm not too clear on how that code works, but I do know that it stops at the await Task.Delay line before finally i hit "step into" (F11) one more time and it somehow just applies the monstrous zoom that was not wanted, without my seeing any code after that being run.
Any workarounds?
Try to set IsInertiaEnabled = false on viewport

How do I show the wait cursor WITH the arrow?

I've got a long running task that I'm launching with await Task.Run. While my task runs, I'd like to show the wait cursor, but the one which also has the arrow. This arrow doesn't exist explicitly in the CursorType enumeration. According to Wikipedia, the normal wait cursor "can be accompanied by an arrow if the operation is being performed in the background." How do I take advantage of this. If I use Mouse.OverrideCursor = Cursors.Wait from the UI thread, I get the normal wait cursor. If I try setting it from my background thread, I get an error. If I use Dispatcher.Invoke, I'm right back to calling it from my UI thread.
Never mind. It's the AppStarting cursor that I'm looking for. Seems like the Wikipedia article was leading me down the wrong road. Who would have though? :D

Thread.Sleep and Painting UI

I have this stoplight program that models a strange intersection near where I live. I am pretty sure I have the logic down. I have functions that represent every possible state of the lights, including yellows. The problem is that none of my yellow lights are painting. Five seconds after a car pulls up to a light and no other cars have passed through green lights, yellow lights for appropriate lights are supposed to turn on for three seconds, and then turn green. For some reason when I step through my program, no yellow lights are painting. Here is my code:
private void WaitThreeSecs()
{
//somehow I think this is to blame
int threeSeconds = 3000;
Thread.Sleep(threeSeconds);
}
private void FromStateOneToTwo()
{
//Stop Countdown Timers
fiveSec.Stop();
thirtySec.Stop();
//Indicate Current State
CurrentState = 2;
//Paint lights
BottomGreen.Fill = gray;
BottomYellow.Fill = yellow; // this never happens
BottomRed.Fill = gray;
//Wait 3 secs
WaitThreeSecs();
btnbottom.Content = "Car Stops";
//Call function that changes the state for other lights to be green
StateTwo();
}
FromStateOneToTwo() is called after the five seconds, but the light is never yellow. I have no idea why this doesn't happen. The light waits 8 seconds from when a button is pressed to when the appropriate light goes straight from red to green, meaning that my 3 second timer is working, but my painting the light is not. (I paint in other function exactly like i do here, and it works fine)
I can show more/all of my code if needed.
You aren't getting a cross-thread InvalidOperation exception, so I'll assume that the provided function runs on the UI thread. This will happen if you invoke it off of a button-click, or the elapsed event of a DispatcherTimer.
By sleeping the UI thread, you don't give it time to paint the screen. It switches colors, then back, without a paint method ever running.
Your best solution is to use a standard Timer so you aren't on the UI thread, then marshal your changes to the UI thread with Dispatcher.BeginInvoke (WPF) or Control.Invoke(WinForms). You can also eliminate Thread.Sleep and make more timers to trigger the next changes.
Use Application.DoEvents right before the WaitThreeSecs() tot force a screen refresh

How to refresh my circular gauges while updating the needle value in threads (C# winforms)?

I use to make a project that reads some data from a serial port and displays these data on circular gauges. I made a thread for receiving data, a thread for sending data and a thread for each gauge to update the needle value.
I use 11 dotnet circular gauges and each gauge contain 2 scale with 2 pointers. In every thread of each gauge I made a loop that update the needle value slowly till it reaches the value I want without this loop the needle jumps suddenly to the value and I don't this to happen so +/- 0.003 on the current value of the pointer till it reaches the value.
My question is that when I run each gauge alone it works fine but when all gauges work at the same time the form freezes and then suddenly all pointers jump to the value how to handle this problem???? (I don't know why this happen it's supposed that each gauge works in a separate thread why the form freezes?)
I want to refresh the needles only not the whole gauge.
(each gauge represents a motor labeled from A to H)
My code:
http://ideone.com/GntXoE
Winforms does not support updating UI controls from a background thread. Whenever you want to update a UI control from a background thread, you need to pass a message from the background thread to the UI thread and perform the update of the control on the UI thread.
One way to do this is to use a System.Threading.SynchronizationContext. Capture the synchronization context into a variable while running on the main UI thread, then pass that context to each of your background threads. When a background thread needs to update a UI control, call context.Post and pass in a callback that will be executed on the UI thread.
Something like this:
context.Post(() => { control.Percent += 10; });
This will keep the UI work in the UI thread where the UI thread message loop will handle redrawing the form and controls as they change state. Using Post() instead of Send() will let your background thread get back to its task immediately without waiting for the UI work to complete. Send() will block the background thread until the UI work completes.

DispatcherTimer and UI refresh limits in C# silverlight

Again I apologize for a question that might be simple to all of you. I have a limited understanding of what goes behind the scenes in Silverlight.
I have a charting app (Visiblox) that I use as a rolling scope updated every 20ms, adding and removing a point. In pseudocode:
List<Point> datapoints= new List<Point>();
Series series = new Series(datapoints);
void timer_tick(){
datapoints.Add(new Point);
datapoints.RemoveAt(0);
// no need to refresh chart, it does refresh automatically
}
When running 6 series in this charting tool, it started to show a bit sluggish. Changing the tick to 10ms made no difference whatsoever, chart was updated at the same speed, so it seems that 20ms is the speed limit (UI or chart?).
I tried with CompositionTarget.Rendering and got the same results: below 20ms there was no difference in speed.
Then I accidentally enabled both and speed doubled. So I tested with multiple threads (2, 3, 4) and speed doubled, tripled and quadrupled. This has no locks yet, as I don't even know what process I need to generate a lock on, but got no data corruption nor memory leaks.
The question I have is why a sluggish chart at 20ms can not run at 10ms but is ridiculously fast when multithreaded? Is the UI refresh process being run faster? Is the chart computation doubled? Or is there a limit to how fast a single DispatcherTimer can be executed?
Thanks!
Edit: I have a background of embedded coding, so when I think of threads and timings, I immediately think of toggling a pin in hardware and hook up a scope to measure process lengths. I am new to threads in C# and there are no pins to hook up scopes. Is there a way to see thread timings graphically?
A DispatcherTimer, which fires its Tick event on the UI thread, is what's considered a low-resolution or low-accuracy timer because its Interval effectively means "tick no sooner than x since the last tick". If the UI thread is busy doing anything (processing input, refreshing the chart, etc.) then it will delay the timer's events. Furthermore, having a bunch of DispatcherTimer's ticking away on the UI thread at very low intervals will also slow down the responsiveness of your application because while the Tick event is being raised, the application can't respond to input.
So as you noted, in order to process data frequently, you should move to a background thread. But there are caveats. The fact that you aren't currently observing corruption or other bugs could be purely coincidental. If the list is being modified on a background thread at the same time the foreground thread is trying to read from it, you will eventually crash (if you're lucky) or see corrupt data.
In your example, you have a comment that says "no need to refresh chart, it does refresh automatically." This makes me wonder how does the chart know that you have changed the datapoints collection? List<T> does not raise events when it is modified. If you were using an ObservableCollection<T> I would point out that each time you remove/add a point you are potentially refreshing the chart, which could be slowing things down.
But if you are in fact using List<T> then there must be something else (perhaps another timer?) that is refreshing the chart. Maybe the chart control itself has a built-in auto-refresh mechanism?
In any event, the problem is a little bit tricky but not completely new. There are ways that you could maintain a collection on a background thread and bind to it from the UI thread. But the faster your UI refreshes, the more likely you'll be waiting for a background thread to release a lock.
One way to minimize this would be to use a LinkedList<T> instead of List<T>. Adding to the end of a LinkedList is O(1), so is removing an item. A List<T> needs to shift everything down by one when you remove an item from the beginning. By using LinkedList you can lock on it in the background thread(s) and you'll minimize the amount of time that you're holding the lock. On the UI thread you would also need to obtain the same lock and either copy the list out to an array or refresh the chart while the lock is held.
Another possible solution would be to buffer "chunks" of points on the background thread and post a batch of them to the UI thread with Dispatcher.BeginInvoke, where you could then safely update a collection.
The key here I think is to realise that Silverlight renders at a maximum frame rate of 60fps by default (customisable through your MaxFrameRate property). That means that the DispatcherTimer ticks will fire at most 60 times per second. Additionally, all the rendering work happens on the UI thread as well so the DispatcherTimer fires at the rate that the drawing is happening at best, as pointed out by the previous poster.
The result of what you're doing by adding three timers is just to fire the "add data" method 3 times per event loop rather than once, so it will look like your charts are going much faster but in fact the frame rate is roughly the same. You could get the same effect with a single DispatcherTimer and just add 3 times as much data on each Tick. You can verify this by hooking into the CompositionTarget.Rendering event and counting the frame rate there in parallel.
The ObservableCollection point made previously is a good one but in Visiblox there is a bit of magic to try and mitigate the effects of that so if you're adding data at a very fast rate the chart updates will be batched up at the rate of the render loop and unnecessary re-renders will be dropped.
Also regarding your point about being tied to the ObservableCollection implementation of IDataSeries, you are entirely free to implement the IDataSeries interface yourself, for example by backing it with a simple List. Just be aware that obviously if you do that the chart will no longer automatically update when data changes. You can force a chart update by calling Chart.Invalidate() or by changing a manually set axis range.

Categories