I'm developing a chat application. For getting frequetly comming request,messages and zone request I'm using one timer and call all methods on timer.now. The problem is that when ever I click on any control in the application this gives me a late response due to the timer running. It first hangs until it completes the timer code then control click event is fire.
So, any help on how to handle this is appreciated, I also tried threading but this didn't help.
Please give me any idea if u have.
Thanks.
Use System.Timers.Timer or System.Threading.Timer instead of the Windows.Windows.Forms.Timer, and inside the Elapced event handler whenever you call methods or properties on UI controls use control.InvokeRequired and control.Invoke.
the problem with the form timer is that it perform the action on UI thread, From msdn:
Windows timer is designed for a single-threaded environment where UI
threads are used to perform processing
Edit: Here is example using System.Timers.Timer:
private System.Timers.Timer _chatTimer = new System.Timers.Timer();
public Form1()
{
InitializeComponents();
_chatTimer.Interval = 1000;//1 seconds
_chatTimer.Elapsed += OnChatTimerElapsed;
_chatTimer.AutoReset = true;
}
private void OnChatTimerElapsed(object sender, System.Timer.ElapsedEventArts e)
{
//code to perform when timer elapsed.
}
Edit2: Another thing to notice that depending on execution time on the elapsed event handler, if the time required to execute the code on it is larger than 1 second then I suggest you to set _chatTimer.AutoReset to false and only start the timer after the previous elapsed event is finished. for example check this.
Related
I'm writing a forms application. I'm adding a piece that allows you to double click on a row of a datagridview control to open a new form with more details. These additional details are pulled from a database, which takes a bit of time to finish.
If I run the DB query from the form's load event, the form doesn't show up until everything in the load event has completed, which can take several seconds.
I want the form to show up instantly when you double click, and all of the fields to be populated once the data is ready.
Is there an event I should be using other than Load?
The standard way to accomplish this is to use a background worker thread and disable the button until the worker thread completes. There is a complete event you can subscribe to on the background worker.
You should use threading. Kick off a thread to do the data retrieval in the form's load event. Introduction to threading
You should use a BackgroundWorker to load the data in a background thread without freezing the UI.
If you really want to load on the UI thread, you should handle the Shown event.
This is an c# example using BackgroundWorker as the other posts metioned that loads unit definitions from .xml an file and changes the status label when it finishes. I stuck in the form intializer, but maybe it is better to start it in an OnLoad() override.
public MainForm()
{
InitializeComponent();
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = false;
bw.WorkerSupportsCancellation = false;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
unitsToolStripLabel.Text = "Loading Units";
bw.RunWorkerAsync();
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
...
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
unitsToolStripLabel.Text = string.Format("{0} Units Loaded", Units.UnitLibrary.WorkingSet.Count);
unitsToolStripLabel.LinkBehavior = LinkBehavior.HoverUnderline;
unitsToolStripLabel.Click += new EventHandler(unitsToolStripLabel_Click);
}
Please explain a little more on why you do not want to use threading/backgroundworker?
Whilst the correct way to do this is the BackgroundWorker thread, a quick and dirty method is to start a timer on the Load event and get the data when the timer expires. Say 10ms is enough for the form to be painted, then you can disable the controls and set the cursor busy while you get the data. But this is still going to lock up the UI thread while the database is busy leading to repainting artifacts eg if part of the window is covered, and doesn't allow you to display progress using a progress bar.
You can let the load event finish, then start another method to pull data from your database. The initialization of the UI can be done after the form has completed loading, but make sure your UI controls are disabled while you're initializing them.
I'm making a Calendar application for myself to use, and to learn.
I've had no trouble until now with mutliple forms, and opening new ones on top of each other, etc.
Here's an example:
private void button1_Click(object sender, EventArgs e)
{
if (ceForm != null) ceForm.Close();
ceForm = new CalendarEventForm();
ceForm.Show();
}
Anyway, I now started to add timers to pop up a 'reminder' form before important events on my calendar will occur (i.e. 1 hour before etc.).
The code sets up the timers when the program is loaded, and then when each timer elapses, this is called:
static void lazyTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
mainForm.ShowReminder((sender as LazyTimer).ReferredEvent);
}
LazyTimer is exactly the same as a System.Timers.Timer except the added propery 'ReferredEvent', which refers to the calendar event that is to be reminded of.
MainForm.ShowReminder() is as follows:
public void ShowReminder(LazyEvent lazyEvent)
{
ReminderForm newReminder = new ReminderForm();
newReminder.LoadEvent(lazyEvent);
newReminder.Show();
}
The weird thing is that ReminderForm crashes. I've tried it with other forms (such as CalendarEventForm, which I know works normally) and they crash too. However, when I try to load the ReminderForm by pressing a button on my main form, it works fine.
Why do my forms crash when loaded (indirectly) by a timer?
Short answer: Use a System.Windows.Forms.Timer, not a System.Timers.Timer.
The reason is that the System.Timer.Timers class will fire the timer event on another thread, and you are not able to directly do UI operations from another thread than the main UI thread.
If it's wrapping a System.Timers.Timer, it will be firing on a thread-pool thread, which means you can't do UI operations there.
Use a System.Windows.Forms.Timer instead, or set the SynchronizingObject in the System.Timers.Timer to a UI object, so that the timer will fire on the UI thread.
EDIT: Another point... personally I'd probably use a lambda expression or anonymous method as the timer's Tick event handler, capturing the relevant event that way and thus avoiding the extra class and the extra method:
// Presumably we've got a local variable here, e.g. currentEvent
timer.Tick += delegate { mainForm.ShowReminder(currentEvent; };
You are running into a threading issue.
Please use System.Windows.Forms.Timer when working with System.Windows.Forms.
The System.Timers.Timer does not invoke the event on the applications event loop, but calls the event handler directly, which leads, in your case, to a cross thread operation which is not supported by Forms, and your application crashes.
In contrast, System.Windows.Forms.Timer will fit seamlessly into the component model of System.Windows.Forms.
My c# WinForm application uses the Elapsed event of a System.Timers.Timer to open a new form. It was pointed out to me (in an earlier question I posted on a different topic) that this was a bad idea; it was suggested I use System.Windows.Forms.Timer.
I've changed my code in response to this suggestion and my application appears to work; however, I'm still rather low on the WinForms learning curve and I'd enjoy feedback on whether or not I've correctly changed my code. (I'm concerned because the old way--the bad way--also appeared to work.)
I have two forms: frmTimer and frmUser. Each form resides in a separate project in the WinForms solution. FrmTimer uses the namespace 'svchostx' and runs from svchostx.exe. FrmUser uses the namespace 'XXXUser' and runs from XXXUser.exe (where XXX is the application's name).
Is it bad to use System.Timers.Timer in this context and, if it is, then have I made the correct changes?
In frmTimer this code:
this.tmTimer= new System.Timers.Timer();
((System.ComponentModel.ISupportInitialize)(this.tmTimer)).BeginInit();
//
// tmTimer
//
this.tmTimer.Interval = 20000;
this.tmTimer.SynchronizingObject = this;
this.tmTimer.Elapsed += new System.Timers.ElapsedEventHandler(this.tmTimer_Elapsed);
private System.Timers.Timer tmTimer;
private void tmTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
Was replaced with this code:
this.timer1 = new System.Windows.Forms.Timer(this.components);
//
// timer1
//
this.timer1.Interval = 20000;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
private System.Windows.Forms.Timer timer1;
private void timer1_Tick(object sender, System.EventArgs e) {
In both the old code and the new code, the timer event checks to see if certain conditions are meet, and when they're meet, then frmUser is opened. FrmUser shows a quiz screen (with math or spelling questions) that the user answers. FrmTimer is never seen and contains only logic to determine when frmUser is opened.
Also, Visual Studio's IntelliSense says this about System.Windows.Forms.Timer: "This timer is optimized for use in Windows Forms applications and must be used in a window." The last part of that sentence confuses me because frmTimer doesn't really have a window (the form is never seen). I'm not sure what is meant by 'must be used in a window'--yes, I am pretty low on the learning curve.
Any advice or help here is appreciated.
The way you are using the System.Timers.Timer is correct. The key to making this timer work in UI scenarios is the SynchronizingObject property. When set to null this timer raises the Elapsed event on a ThreadPool thread. When set to an instance of an ISynchronizeInvoke object it raises the event on the thread hosting that object. If that ISynchronizeInvoke instance is none other than a control or form then the hosting thread is the thread that the control or form was created on...the main UI thread.
The System.Windows.Forms.Timer can only be used in UI scenarios because it creates a window handle. You do not actually see this window get created, but it is there. And of course this timer always raises its Tick event on the UI thread.
Use System.Windows.Forms.Timer for interaction with WinForms.
System.Timers.Timer is built for other purposes, like background operations and services, and its not synchronized with UI Threads.
Have also a look here.
Read about the three types of timers available in .net from here. There is really nothing wrong with using the System.Windows.Forms.Timer for UI programming.
If two windows are created in the same thread, then anything which stalls the UI thread for one will stall it for both. On the other hand, controls from one window can freely manipulate the other window without requiring any explicit synchronization. If you use a forms.Timer, your new window can only be created when the UI is idle; unless you endeavor to make it otherwise, your new form will use the same thread as the one with the timer. If you use another type of timer, your new form can appear even when all other UI threads are busy; the new form will not share a thread with other forms. Note that since the form's thread won't die until the form is closed, it may be better to create a new thread (from the timer event) than hog a thread-pool thread.
I am struggling to find a way to create the Forms functionality that I want using C#.
Basically, I want to have a modal dialog box that has a specified timeout period. It seems like this should be easy to do, but I can't seem to get it to work.
Once I call this.ShowDialog(parent), the program flow stops, and I have no way of closing the dialog without the user first clicking a button.
I tried creating a new thread using the BackgroundWorker class, but I can't get it to close the dialog on a different thread.
Am I missing something obvious here?
Thanks for any insight you can provide.
You will need to call the Close method on the thread that created the form:
theDialogForm.BeginInvoke(new MethodInvoker(Close));
Use a System.Windows.Forms.Timer. Set its Interval property to be your timeout and its Tick event handler to close the dialog.
partial class TimedModalForm : Form
{
private Timer timer;
public TimedModalForm()
{
InitializeComponent();
timer = new Timer();
timer.Interval = 3000;
timer.Tick += CloseForm;
timer.Start();
}
private void CloseForm(object sender, EventArgs e)
{
timer.Stop();
timer.Dispose();
this.DialogResult = DialogResult.OK;
}
}
The timer runs on the UI thread so it is safe to close the form from the tick event handler.
If you really just want a modal dialog then I found this to be the best solution by far: http://www.codeproject.com/KB/miscctrl/CsMsgBoxTimeOut.aspx (read the comments section for a small modification).
If you want to display your own form modally, then the solution from adrianbanks is best.
you can Invoke the close from your background thread
I need to be able to disable a button for 1.5 seconds at a time for an application I'm writing. An image is displayed, a user clicks a button, and then another image is displayed. I need to make sure that the user doesn't click the button again too quickly.
So, when the image is displayed, I call this function:
//when a new image is displayed, start the timer and disable the 'done' button
//for 1.5 seconds, to force people to stop pressing next so quickly
System.Timers.Timer mTimer;
void TimerStart() {
Done.IsEnabled = false;
mTimer = new System.Timers.Timer();
mTimer.Interval = 1500;
mTimer.Start();
mTimer.Elapsed += new System.Timers.ElapsedEventHandler(TimerEnd);
}
The TimerEnd code looks like:
void TimerEnd(object sender, EventArgs eArgs) {
if (sender == mTimer){
Done.IsEnabled = true;
mTimer.Stop();
}
}
The 'Done.IsEnabled' line gets hit, but the button is not reenabled and the timer doesn't stop firing. What am I doing wrong here? If it matters, this is a WPF app.
Use DispatcherTimer instead
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(someInterval);
timer.Tick += new EventHandler(someEventHandler);
timer.Start();
private void someEventHandler(Object sender, EventArgs args)
{
//some operations
//if you want this event handler executed for just once
// DispatcherTimer thisTimer = (DispatcherTimer)sender;
// thisTimer.Stop();
}
Basically you are trying to debounce the button, to prevent too quick clicks. Rather than use a timer save the previous click time in millis, if the button is clicked again within a short time ignore the next event.
The timer event is raised on a different thread. When working with the winforms controls, you need to make sure you Invoke them from the same thread where they were called.
When working with WPF there is no guarantee that updates made to UI controls on non-UI threads will work as expected. In many cases you will get an exception when you do this.
In your Timer elapsed handler you need to use the BeginInvoke/EndInvoke paradigm and put your button enabling logic in there to ensure that this code runs on the UI thread instead of Begin/End Invoke
There is a SynchnornizationContext available as well which can be accessed by calling SynchronizationContext.Current . You'll need to cache this before you make the timer call since SynchronizationContext.Current will be null in non-UI threads.
This link talks about this as well.