question about System.Windows.Forms.Timer - c#

I am building a WinForms application reading from a socket data and charting lines.
I am using System.Windows.Forms.Timer to trigger each second the event that
gets data from a queue filled by a socket
redraws lines on the chart
My Question is about the Timer object: I have one Timer object for each WinForm having a chart to redraws; so suppose I have 20 chart, I will have 20 forms with a total of 20 Timers.
Is this a good approach? I decided this based on the following(please correct me if I am wrong )
Forms.Timer instance doesn't create a Thread on my application, but just triggers the event on receiving a WM_TIMER event from the message pump of the Form.
it lives in the same thread of the GUI so I can directly access each element of my forms without worrying too much.
Are too much timers a good approach or could I have drawback?
Thanks
AFG

This is a good approach, although you might want to reuse the timers instead of making a separate timer for each form.
For example, you could make a static Timer object and add a Tick handler in the form constructor. Remember to unsubscribe from the event when the form closes (in Dispose or OnClose), or your forms will never die.

maybe better approach is to use a worker thread to receive data and use event fired from that worker thread to notify the UI to redraw itself.

Why not redraw the line straight away when the data is received by the socket?

Related

C# WinForms :- Why Thread Timer tick event not elapsed when UI is doing some other operation?

In my application UI, I am updating one of grid through Windows Timer tick every 1 sec.
It's not working properly when I am doing some other UI operations belongs to another windows forms(this is basically using tabbed forms)
I added trace for Timer_Tick event and logged in to file.
We found there is an missing of log data, when another UI operation going on (Open and closing of another windows form). Timer_Tick not hitting at this time.
Any suggestions...?
The issue is that the UI is running in a single thread. Any long-running blocking operation on that thread - like opening a form, running some code in response to a button click, etc - will prevent the timer from firing. This is the nature of single-threaded programming.
If you absolutely need to run code every second, regardless of what is happening in the UI thread, you'll need to use a second thread.
Related Links:
System.Threading.Thread documentation
System.Threading.Tasks.Task documentation
System.Threading.Timer documentation
And very important, for interacting with your UI from any of the above:
System.Windows.Forms.Control.Invoke method documentation
System.Windows.Forms.Control.InvokeRequired property documentation
The System.Windows.Forms.Timer tick event executes on the UI thread. If the UI thread is busy doing something else, then the timer tick handler will have to wait.
The tick events for System.Threading.Timer and System.Timers.Timer happen on threadpool threads, so they can execute while the UI thread is busy. If you need to update the UI from your tick handler, you can call BeginInvoke, and the UI update will happen when the UI thread is free.
There's no need to start a different thread or a BackgroundWorker that executes a Sleep loop.
You can run it on a BackgroundWorker since it just happens every 2 seconds without user interaction. For more details about BackgroundWorker, check this article "http://www.dotnetperls.com/backgroundworker" it's very easy to understand.
BackgroundWorker makes threads easy to implement in Windows Forms. Intensive tasks need to be done on another thread so the UI does not freeze. It is necessary to post messages and update the user interface when the task is done.

How to make 2 forms on 2 separate threads in C# winform application

I am developing an interface in my C# 4.0 winform application, to fire some sms in bulk. Each message content is different so that I have to fire messages one by one. I have a form from where the end user can shoot smss, it may be more than a thousand.
I want to manage a queue. If the user shoots a sms then it will be submitted to the queue and the queue will send sms one by one.
So I have to create a form to manage the queue. The problem is that I want my application to work normally and in the background the queue sends sms.
So how can I achieve this task? I have tried BackGroundWorker, but I don't know how to maintain a separate thread with a form.
All forms must be on the UI thread. The sending of the SMS should be performed by the BackgroundWorker.DoWork event. The updating of the form is then done by BackgroundWorker.RunWorkerCompleted event.
The UI thread is main thread of the application for SWF (winforms)
If you are using C# 4.0 or above, you may also want to investiage the Take Parallel Library (http://msdn.microsoft.com/en-us/library/dd460717.aspx). But I would first get BackgroundWorker implementation to work. Then use TPL to send simultaneous SMS. Could really speed things up.
you have to create one thread (called worker thread) which runs for the life your application.
you have to have a queue or even better a concurrent queue http://msdn.microsoft.com/en-us/library/dd267265.aspx
the worker thread wait when an item (sms) appears in the queue, takes that item and do its work.
the UI is completely decoupled from that work.
this is most basic use of the class Thread.
Background worker is least suitable solution. obviously you can use a washing machines to build a house but most people use bricks.
You can start Thread then create new instance of form on it (with no parent) and then start message loop (such code located in Main method of project's template).
Remember, any form (generally any GDI object) can be used only on thread that creates it. E.g you can't create child form on another thread, then parent's. Every GUI thread must run message loop.

Event Occurring in the Form Life Cycle in windows form

Which Event is occurred before Form Load event??
Because I have a timer control for which I have written timer.start() method in form load event and current time is displayed in Label Control.
Timer starts when the form Loads but it takes few seconds to show the time, so is there any other way to show the time fast?
Have a function called ShowTheTime. Call it in form load. Also start your timer in form load. Your timer handler also calls ShowTheTime.
Am I missing something here? It seems kind-of trivial.
You're probably using the Timer from the Forms namespace. That component is tightly coupled to the UI. You should take a look at the Threading.Timer class which is not tied to the UI. You will have complete control over it and can start it from the Form's constructor (or even earlier, before the form is created.)
This is a very old article but the concepts in it still hold. (Compares the different Timer classes.) Basically an abbreviated version of the previous article.

Is there an 'Application.DoEvents' at the form level?

I currently have an application that spawns multiple instances of a single win form. Each instance of the form has a timer which updates a number of controls and some of the properties of the form itself at rate of approx 1 tick/sec. Once the application reaches a certain number of forms it stops painting the 'updates' that occur within the timer ticks.
I want to hold the UI thread at the bottom of the timer and allow the form to repaint without calling Application.DoEvents (my understanding is that Application.DoEvents() handles all pending window messages across the application (which could include other timers 'ticks'? - not sure) when all I want it to process is the redrawing of the form now that a number of the controls have been updated).
It's not clear to me why you want to call DoEvents at all. Why not just let the window repaint itself appropriately? What's wrong with the way it behaves at the moment?
Calls to DoEvents usually indicate that something should be in a background thread - in your case it sounds like it might actually just be that you've got too many events going on. If your GUI is so complex that it can't redraw itself in a second, it sounds like that's probably a design issue with the UI itself.
If you just want the form or a specific control to redraw itself, just call Control.Refresh on the form/control in question.
That being said, this is usually (like Application.DoEvents) a sign that a redesign is in order. If you have long running processes like this, it's a much better idea to push the work into a BackgroundWorker, which will make the actual computational work run in a background thread, and prevent the UI from becoming unresponsive.
There are three categories of Windows messages that are dispatched by the message loop and a call to Application.DoEvents(). First are messages that are sent with SendMessage(). They are important, they need to be dispatched right away because there is some other program waiting on the result of the SendMessage() call. They are not put on the message queue, Windows calls the window procedure directly.
Then there are messages that are put on the message queue with PostMessage(). They can wait, they are merely notifications. All of the keyboard and mouse messages fit that category.
Then there are the low priority messages, WM_TIMER and WM_PAINT. They only get dispatched when there's nothing else to do, no SendMessage is pending and the message queue is empty.
Sounds like you got yourself into a situation where you starving Windows so badly that it can't get around to dispatching those low priority message anymore. Probably neither getting timer Ticks nor Paint events anymore. Calling DoEvents only once a second will certainly do that. This is bad, your program is now affecting the operation of other programs as well. You'll have to fix that. Do so by re-architecting your app so you no longer depend on DoEvents.
My 2c:
Having a timer in each form is going to slow down performance to a crawl. Each window at each second interval is going to request the application to switch to that window's "context" and execute some code. That whole switch is likely longer than your code actually takes to run. Couple that with the likely fact that all of your forms are in the same "context".
Instead consider something like this if possible:
List<MyForm> listofmyform;
Timer t = new Timer()
t.tick += delegate
{
foreach(MyForm thisform in listofmyform)
thisform.DoUpdate();
}
This only uses one timer to update all of your forms, only requires one "context switch" and will likely cure some performance problems you're having.

C# Winforms How to update toolStrip in function

I'm building a UI for a program, and I can't figure out why my progress bar won't become visible after the convert button is clicked.
private void convertButton_Click(object sender, EventArgs e)
{
toolStripProgressBar.Visible = true;
...
toolStripProgressBar.Visible = false;
}
I ran into a similar problem with tkinter in Python, and I had to call a function to update the idle tasks. Is there a way to do this with windows forms without using threads?
Edit: On a side note, this is a progress bar in a toolStrip that also contains a label that gets updated with status bar text. Is there any way to get the label on the left side and the progress bar on the other instead of right next to each other on the left?
Well, there is a way to do this without using threads (Application.DoEvents) but I strongly recommend against you using it. Re-entrancy is nasty, and you really don't want the UI thread tied up at all.
Use BackgroundWorker instead - it's easy, and it's pretty much designed for progress bars. It takes the hassle out of using a separate thread and reporting progress back to the UI thread. No need for Control.Invoke etc - it takes care of that for you.
There are lots of tutorials for BackgroundWorker - it shouldn't take you too long to get going with it.
Per the question you asked for the way to do this WITHOUT threads, that is to do it with Application.DoEvents();. (Just add that call right after setting the progress bar as visible.)
Now I do agree with Jon Skeet though that BackgroundWorker is a better way of doing this, but it does use a separate thread.
You need to execute your process in a thread separate from the UI thread, and then have it periodically report back to the UI thread with it's progress. If your convert operation is working inside the UI thread, it will simply go unresponsive until the operation is complete.
The progress bar can only become visible when it is allowed to paint which occurs during the processing of messages. Message processing cannot normally happen while you are in the middle of an event handler. If you want the progress bar to show up you will have to set the visiblitity to true, start a background thread to complete the work and return from the handler.
I'm guessing the problem is that the "..." in your code is a long-running process. UI updates are not instantaneous, but must run through the message queue in windows and then be painted to the screen. The queue is pumped and painting takes place in the same thread as your events.
As a result, any long-running tasks need to be moved to a different thread. More than that, your line line of code needs to called after that thread terminates. Otherwise you set the progress bar and then immediately turn it off again.
One way to do that is with a BackgroundWorker control.
Here go two links trying to explain you how things work:
(1) (2)
Now, I will try to explain it as shortly as I can. Most of what happens inside a windows forms application happens in a single thread, usually the same thread Main() runs in. If you open Program.cs, you will see that Main() has a line that looks like the following:
Application.Run(new Form1());
If you debug the application at any moment and examine the call stack, you will see it will trace back to that Run method. This means that a Windows Forms application is in fact a continuous run of the Run method. So, what is Run doing? Run is eating a message queue through which Windows sends messages to it. Run then dispatches those messages to the correct controls, which themselves do things like add text which corresponds to the key being pressed, redraw themselves, etc. Notice that all this happens during and endless loop running alongside a single thread, so weather you are typing or simply moving the window around, loads of those messages are being passed onto the application, which in turn is processing them and reacting accordingly, all in that single thread. Controls can also send messages to themselves through the queue and even you can place messages in the pump via Control.BeginInvoke. One of the things those controls do is to raise events according to what happens. So, if you click a button, the code you've written to handle that click will ultimately and indirectly be run by the Application.Run method.
Now, what is happening with your code is that even though you are changing the visible status of your progress bar to visible and then updating its Value, you are then changing its visibility to false, all in the same method. This means that only after you leave the method, will Application.Run() be able to continue iterating and consuming the message queue, effectively asking the progress bar to update its display. When that happens, you've already left the progress bar's visibility to false, the last thing you did before exiting the method. DoEvents() is a quick and dirty workaround to your problem as it reads the messages in the queue and processes them. I don't really feel comfortable using it as it can bring reentrancy problems.
Using threads is a good solution, but I would recommend using a ThreadPool thread instead of a custom thread in this kind of situation, as I tend to use custom threads only in cases where I have a limited number of long lived threads and I need to control their life cycles. The easiest and most practical way to use threads is to use the BackgroundWorker component, even though I would recommend going through the pains of understanding how to do Windows Forms multithreading with delegates if you want to really understand what is going on.
My solution is to call refresh on the status strip.
I believe this causes the UI thread to repaint the status strip.
toolStripStatusBar1.PerformStep();
statusStrip1.Refresh();
This is for .NET 4.0. Even though this question is old it was the first I found on googling this issue.

Categories

Resources