I'm doing a small test project before I use System.Threading.Timer in a Windows Service project. It's working wonderfully, however the timer stops on its own after a minute or two.
The full source for the test project is:
using System;
using System.Windows.Forms;
using System.Threading;
namespace studyTimers {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
TimerCallback timerDelegate = new TimerCallback(tick);
System.Threading.Timer testTimer = new System.Threading.Timer(timerDelegate, null, 1000, 1000);
}
void tick(Object obj) {
if (label1.InvokeRequired) {
label1.Invoke(new MethodInvoker(() => tick(obj)));
} else {
label1.Text = DateTime.Now.ToString();
}
}
}
}
The goal is obviously to update a label with the current time. I am noticing that updating stops after a bit. Why would this be?
If you need a timer on a Windows Form then drop a System.Windows.Forms.Timer onto the form - there's no reason to use a System.Threading.Timer unless you need better resolution than 55 ms.
The reason the timer "stops" is because it's being garbage-collected. You're allowing it to go out of scope in the Form1_Load method because you only declare it as a local variable. In order to keep the timer "alive", it needs to be a private field on the form class so that the GC knows it's still needed.
In other words:
public partial class Form1 : Form
{
private System.Threading.Timer testTimer;
...
public void Form1_Load(object sender, EventArgs e)
{
TimerCallback timerDelegate = new TimerCallback(tick);
testTimer = new System.Threading.Timer(timerDelegate, null, 1000, 1000);
}
}
But again, in this case it's simplier to use System.Windows.Forms.Timer, which is an actual component in the toolbox that you can just drop onto the form.
Edit - As the comments now reveal, if this is just a test app and the real application is in a Windows Service, you cannot use System.Windows.Forms.Timer for that. Just remember not to let your System.Threading.Timer go out of scope.
Garbage collector collected the timer object, you should keep a reference to it.
this post will help: http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx
Related
I'am using System.Threading.Thread.Sleep(50); but i think is to slow, I'dont know why, but it is.
Look at my code:
clickButton();
System.Threading.Thread.Sleep(SLEEP_AFTER_CLICK_PAGE);
I want first clickButton(); and after I need sleep program. But if i run code, program first sleep and after sleep call method clickButton(); ?Why? I don't understand this...
Program is only in one thread.
EDIT code:
private void timer1_Tick(object sender, EventArgs e)
{
clickButton();
timer1.Stop();
System.Threading.Thread.Sleep(SLEEP_AFTER_CLICK_PAGE);
timer1.Start();
}
private void clickButton()
{
webBrowser1.Document.GetElementById("skip_ad_button").InvokeMember("click");
}
I suspect that the behaviour you are expecting is:
Click a button
Update a bunch of stuff (visibly)
Sleep
But what happens is the visible update doesn't happen until after the sleep...
You need to force the change to the UI before you sleep, as you are preventing it. You can normally do this by adding...
Application.DoEvents();
Before the sleep.
Thread.Sleep does all manner of weird stuff. It might be that the invokation of the click is stored on some queue and that queue is affected by Sleep. I don't know exactly but I know that Sleep should be avoided at all costs.
I suggest you use two timers instead of one. One for clicking, one for waiting, that enables the first timer again. If you do this, you let your application do its stuff while you are waiting. With Thread.Sleep it stops whatever it is doing until the time is up.
Like this:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
public partial class Form1 : Form
{
private System.Windows.Forms.Timer tmrClick = new System.Windows.Forms.Timer();
private System.Windows.Forms.Timer tmrWait = new System.Windows.Forms.Timer();
public Form1()
{
InitializeComponent();
tmrClick.Interval = 2000;
tmrClick.Enabled = true;
tmrClick.Tick += tmrClick_Tick;
tmrWait.Interval = 2000; //SLEEP_AFTER_CLICK_PAGE
tmrWait.Enabled = false;
tmrWait.Tick += tmrWait_Tick;
}
private void tmrClick_Tick(object sender, EventArgs e)
{
label1.Text = "CLICK";
tmrClick.Stop();
tmrWait.Start();
}
private void tmrWait_Tick(object sender, EventArgs e)
{
label1.Text = "WAIT DONE";
tmrWait.Stop();
tmrClick.Start();
}
}
So I've got an application that employs a filesystemWatcher and triggers an event just fine. The FSW will trigger a bunch of times pretty close together. I want to create a function that triggers say an hour after the last time the FSW was triggered.
I first tried using a backgroundworker: (All code is shortened for clarity)
namespace Devo
{
public partial class Form1 : Form
{
BackgroundWorker bw = new BackgroundWorker();
private void fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
if (bw.IsBusy)
{
bw.CancelAsync(); //this is to, in a way, reset the timer for the delayed method.
}
//do a lot of stuff
bw.RunWorkerAsync();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
Stopwatch sw = new Stopwatch();
sw.Start();
while(sw.ElapsedMilliseconds < 180000)
{
if (bw.CancellationPending == true)
{
sw.Stop();
sw.Reset();
e.Cancel = true;
return;
}
}
sw.Stop();
sw.Reset();
DelayedMethod();
}
}
}
This didn't work as the second time bw.RunWorkerAsync() was called it was apparently busy, even though the call to bw.CancelAsync().
My next attempt involved a regular thread as I read somewhere on SO (can't find the link now) that one could not "restart" a backgroundWorker as I am trying to do.
The thread attemp is nearly identical but I thought I'd try in since there might be some constraints within the backgroundWorker that is not present in a regular thread. I thought.
namespace Devo
{
public partial class Form1 : Form
{
Thread PWC_counter_thread = new Thread(PWC_Counter);
private void fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
if (PWC_counter_thread.IsAlive)
PWC_counter_thread.Abort();
//do a lot of stuff
PWC_counter_thread.Start();
}
static void PWC_Counter()
{
Thread.Sleep(180000);
DelayedMethod();
}
}
}
But this gave me the same error. On the second call to PWC_counter_thread.Start() is was busy.
I'm assuming that a race condition is not present as the second thread waits for, in this example, 3 minutes, and the initial FSW method takes a good full second to execute, therefore I believe that the call to .Abort() and .CancelAsync() both are done before their respective methods are completed.
Now for the questions:
Is it possible to restart a thread in the fashion I am trying? If so, what am I doing wrong?
Should I delay my method call in another way? If so, tips?
EDIT/UPDATE/SOLUTION
I never got starting and stopping a thread to work as I wanted so I found another solution to my situation.
The situation was that I had a second thread that worked as a sort of timer where it would call a method after a set amount of time. My first thread did some work and upon finishing it would start the second thread. If the first thread got fired up again before the timer-thread had finished it was supposed to kill the thread and restart it.
This proved, for me, to be difficult to get the way I wanted. So I instead took another approach towards my wanted end result. Instead of restarting the thread I simply restarted the stopwatch that my second thread was using as a counter. This gave me the result I wanted. It's probably bad practice but it works.
In your BackgroundWorker example you probably have an issue with racing. CancelAsync(), as its name implies, is an asynchronious call, meaning that BackgroundWorker does not stop working immediately and it might still work when try to restart it. To avoid that, you should subscribe to RunWorkerCompleted event and wait for it to fire before calling bw.RunWorkerAsync(); again. For example:
public Form1()
{
bw = new BackgroundWorker();
bw.RunWorkerCompleted += OnCompleted;
}
private BackgroundWorker bw;
private ManualResetEvent completed = new ManualResetEvent(false);
private void OnCompleted(object sender, RunWorkerCompletedEventArgs e)
{
completed.Set();
}
private void fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
if (bw.IsBusy)
{
bw.CancelAsync();
completed.WaitOne();
}
//do a lot of stuff
completed.Reset();
bw.RunWorkerAsync();
}
You have multiple issues with your Thread-based example.
You should never call Thread.Abort(). Instead, you should implement a cancellation mechanism, similar to that of BackgroundWorker. Make a bool field (_isCancelled or something) and check it periodically in thread delegate.
You can not reuse a Thread object. You should always create a new one.
You would be best off encapsulating this in a class, and use a System.Threading.Timer to detect the inactivity.
Here's an example I put together. The idea is that you create an InactivityDetector with the appropriate inactivity threshold (an hour in your case) and a callback method that will be called when that period of inactivity is exceeded.
You have to call InactivityDetector.RegisterActivity() whenever activity is detected (e.g. in your case a file creation is detected).
Once the inactivity callback has been issued, it will not be called again until RegisterActivity() has been called again (this prevents multiple callbacks for the same period of extended inactivity).
Your code would pass DelayedMethod for the inactivity Action delegate.
Note that the callback is on a separate thread!
(Also note that I didn't put in any parameter validation, to keep the code shorter.)
using System;
using System.Threading;
namespace ConsoleApp1
{
sealed class Program
{
void test()
{
using (var inactivityDetector = new InactivityDetector(TimeSpan.FromSeconds(2), inactivityDetected))
{
for (int loop = 0; loop < 3; ++loop)
{
Console.WriteLine("Keeping busy once a second for 5 seconds.");
for (int i = 0; i < 5; ++i)
{
Thread.Sleep(1000);
Console.WriteLine("Registering activity");
inactivityDetector.RegisterActivity();
}
Console.WriteLine("Entering 3 second inactivity");
Thread.Sleep(3000);
inactivityDetector.RegisterActivity();
}
}
}
static void inactivityDetected()
{
Console.WriteLine("Inactivity detected.");
}
static void Main(string[] args)
{
new Program().test();
}
}
public sealed class InactivityDetector: IDisposable
{
public InactivityDetector(TimeSpan inactivityThreshold, Action onInactivity)
{
_inactivityThreshold = inactivityThreshold;
_onInactivity = onInactivity;
_timer = new Timer(timerCallback, null, (int)inactivityThreshold.TotalMilliseconds, -1);
}
public void RegisterActivity()
{
_timer.Change(-1, -1);
_timer.Change((int)_inactivityThreshold.TotalMilliseconds, -1);
}
private void timerCallback(object state)
{
_timer.Change(-1, -1);
_onInactivity();
}
public void Dispose()
{
_timer.Dispose();
}
private readonly TimeSpan _inactivityThreshold;
private readonly Action _onInactivity;
private readonly Timer _timer;
}
}
I have gotten this error:
An unhandled exception of type 'System.InvalidOperationException'
occurred in System.Windows.Forms.dll
Additional information: Cross-thread operation not valid: Control
'Redlight' accessed from a thread other than the thread it was created
on.
Redlight and Greenlight are pictureBoxes.
Basically, all I want it to be able to do is alternate between each picture every second.
I searched on this website for similar errors, I see it has to do with "Invoking", but I don't even know what that is, can someone enlighten me?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
namespace EMCTool
{
public partial class EMCTool_MainForm : Form
{
bool offOn = false;
public EMCTool_MainForm()
{
InitializeComponent();
}
private void EMCTool_MainForm_Load(object sender, EventArgs e)
{
System.Threading.Timer timer = new System.Threading.Timer(new System.Threading.TimerCallback(timerCallback), null, 0, 1000);
}
private void timerCallback(object obj)
{
if (offOn == false)
{
Redlight.Show();
offOn = true;
}
else
{
Greenlight.Show();
offOn = false;
}
}
}
}
You get the Cross-thread error when you try to update a UI element from any thread it was not created on.
Controls in Windows Forms are bound to a specific thread and are not thread safe. Therefore, if you are calling a control's method from a different thread, you must use one of the control's invoke methods to marshal the call to the proper thread. This property can be used to determine if you must call an invoke method, which can be useful if you do not know what thread owns a control.
Refer here for more
Try this .This works fine for me
if (pictureBoxname.InvokeRequired)
pictureBoxname.Invoke(new MethodInvoker(delegate
{
//access picturebox here
}));
else
{
//access picturebox here
}
In WinForms projects better use the System.Windows.Forms.Timer as it calls the Tick event on the UI-thread automatically:
private System.Windows.Forms.Timer _timer;
private void EMCTool_MainForm_Load(object sender, EventArgs e)
{
_timer = new System.Windows.Forms.Timer { Interval = 1000 };
_timer.Tick += Timer_Tick;
_timer.Start();
}
private void Timer_Tick(object sender, EventArgs e)
{
if (offOn) {
Greenlight.Show();
} else {
Redlight.Show();
}
offOn = !offOn;
}
Alternative solution would be to use System.Timers.Timer which has SynchronizingObject property so set this, and it will work:
timer.SynchronizingObject = This
Or to use System.Windows.Forms.Timer as it won't raise exception (it raises Tick event on UI thread).
trying to run a function without putting it in the Main() when the program is run.
how do I start the new created function?
trying to call RunMix() in the Main() but get an error because of the lable1
namespace mixer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
int i = 0;
public void RunMix()
{
while (i == 0)
{
label1.Text = knob1.Angle.ToString();
Application.DoEvents();
}
}
private void Form1_Load(object sender, EventArgs e)
{
RunMix();
}
}
}
In a console application, the Main() method is the entry point into the application. You have to put you code to start the application in there.
If you only want to test the function you can use the NUNIT or the Microsofts Unit Testing Framework. Otherwise you have to call the function from the Main().
Alright my first answer was completely off the topic because of your mysterious question. Now that you have updated it I have better - not complete - understanding of what do you mean.
Looking at code I guess what you are trying to do is to change the value of label when knob1 control's angle changes. If knob1 is a control it should have a change event and you should change value of label1 inside knob1_change event handler. If knob1 doesn't have any event - highly unlikely - then you should use a timer instead. Loop is simply a bad idea in your situation. Timer should work like this
Timer timer = new Timer();
public void RunMix(object sender, EventArgs e)
{
label1.Text = knob1.Angle.ToString();
}
private void Form1_Load(object sender, EventArgs e)
{
timer.Interval = 100;
timer.Tick += new EventHandler(RunMix);
timer.Start();
}
Stop timer when form is closed or use activate/deactivate cycle depending upon your requirement.
You can't have another method besides Main as an entry point for the app.
For ex you can't start a program from a function like this:
public static MyMain(string[] args)
{
}
This is a java code for the same but i don't know the same in C#.
But i think it can be possible in C# too.
class staticEx {
static
{
System.out.println("Inside Static
Block");
System.exit(0);
} }
The above code is tested and got it from here while GOOGLEing.
There can be a possibility of similar thing in C# as well.
In my application I am using a timer to check for updates in an RSS feed, if new items are found I pop up a custom dialog to inform the user. When I run the check manually everything works great, but when the automatic check runs in the timers Elapsed event the custom dialog is not displayed.
First of all is this a thread issue? (I am assuming it is because both the manual and automatic check use the same code).
When I run the automatic check, do I have to invoke the method that runs the check from the Timers Elapsed event handler?
Is there something I need to do in my custom dialog class?
Edit:
this is a winforms application.
Here is an example of what the code is like. (Please don't point out syntax errors in this code example, this is just a simple example not real code).
public class MainForm : System.Windows.Forms.Form
{
//This is the object that does most of the work.
ObjectThatDoesWork MyObjectThatDoesWork = new ObjectThatDoesWork();
MyObjectThatDoesWork.NewItemsFound += new NewItemsFoundEventHandler(Found_New_Items);
private void Found_New_Items(object sender, System.EventArgs e)
{
//Display custom dialog to alert user.
}
//Method that doesn't really exist in my class,
// but shows that the main form can call Update for a manual check.
private void Button_Click(object sender, System.EventArgs e)
{
MyObjectThatDoesWork.Update();
}
//The rest of MainForm with boring main form stuff
}
public class ObjectThatDoesWork
{
System.Timers.Timer timer;
public ObjectThatDoesWork()
{
timer = new System.Timers.Timer();
timer.Interval = 600000;
timer.AutoReset = true;
timer.Elapsed += new new System.Timers.ElapsedEventHandler(TimeToWork);
timer.Start();
}
private void TimeToWork(object sender, System.Timers.ElapsedEventArgs e)
{
Update();
}
public void Update()
{
//Check for updates and raise an event if new items are found.
//The event is consumed by the main form.
OnNewItemsFound(this);
}
public delgate void NewItemsFoundEventHandler(object sender, System.EventArgs e);
public event NewItemsFoundEventHandler NewItemsFound;
protected void OnNewItemsFound(object sender)
{
if(NewItemsFound != null)
{
NewItemsFound(sender, new System.EventArgs());
}
}
}
After reading some of the comments and answers, I think my problem is that I am using a System.Timers.Timer not a System.Windows.Forms.Timer.
EDIT:
After changing to a Forms.Timer initial testing looks good (but no new items exist yet so have not seen the custom dialog). I added a bit of code to output the thread ID to a file when the update method is called. Using the Timers.Timer the thread ID was not the GUI thread, but using the Forms.Timer the thread ID is the same as the GUI.
Which timer are you using? System.Windows.Forms.Timer automatically fires the event on the UI thread. If you are using other one you will need to use Control.Invoke to call the method on UI thread.
You should use Forms.Timer here, or if you use other kind of timers, serialize calls to UI with .Invoke()
Is your application a WPF-Application? If so, you must delegate the work from your background-thread to the Dispatcher associated with the UI thread.
Post some code, so you can get better help and have a look at the Dispatcher class http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke.aspx
private static System.Threading.SynchronizationContext _UI_Context;
//call this function once from the UI thread
internal static void init_CallOnUIThread()
{
_UI_Context = System.Threading.SynchronizationContext.Current;
}
public static void CallOnUIThread(Action action, bool asynchronous = false)
{
if (!asynchronous)
_UI_Context.Send((o) =>
{
action();
}, null);
else
_UI_Context.Post((o) =>
{
action();
}, null);
}