Can't start timer from a different thread - c#

I am working on a program where I need to activate a timer from a different thread. I've shortened the code to this example below.
static class Program
{
public static System.Windows.Forms.Timer TimerVideo = new System.Windows.Forms.Timer();
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
TimerVideo.Interval = 1000;
TimerVideo.Tick += new EventHandler(TimerVideo_Tick);
new Thread(() =>
{
test RunTimer = new test();
RunTimer.StartTimer();
}).Start();
Application.Run();
}
private static void TimerVideo_Tick(object sender, EventArgs e)
{
Console.WriteLine("Running");
}
}
class test
{
public void StartTimer()
{
Program.TimerVideo.Start();
}
}
Even if I have to code the timer in the class that would be fine with me, but I did try that and it didn't work either, namely the timer did not fire and nothing was printed out to the console.

System.Windows.Forms.Timer is meant to be run from a UI thread. If you want a timer that fires on a different thread, you can use System.Timers.Timer, e.g.:
TimerVideo = new System.Timers.Timer();
TimerVideo.Interval = 1000;
TimerVideo.Elapsed += (o, e) => Console.WriteLine("Running");
TimerVideo.Start();

Since the timer was created in other thread, you need to call it's methods using Invoke.
https://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/zyzhdc6b(v=vs.110).aspx

Related

TimerTick wont trigger ever

I've created simple class which will behave like my service class, because I've included that class in Topshelf.
Class is simple it just imports some files to db and prints it after it.
Here is the definition:
class ConverterService
{
private FileSystemWatcher _watcher;
private readonly System.Timers.Timer timer;
public ConverterService()
{
ImportAllFiles();
timer = new System.Timers.Timer(10){AutoReset = true};
timer.Elapsed += Timer_Elapsed;
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
PrintFiles();
}
catch(Exception ex)
{
}
}
But problem is Timer_Elapsed is never executed..
I don't know why..
ImportAllFiles() triggers successfully but Timer_Elapsed method is never fired, and I wanted to execute that method every second for example
Thanks guys
Cheers
You need to call timer Start():
timer = new System.Timers.Timer(10){AutoReset = true};
timer.Elapsed += Timer_Elapsed;
timer.Start();
or alternative :
timer.Enabled = true;

How to use timer outside main method in a console application

I have a method in a class that returns the data as List.I need to use timer event for this method to execute in different intervals to check the data.And I need to get the return object from the first method to another method.And I have to call the second method from the Main mehtod in console application.
public class clsSample
{
private static List<string> GetData()
{
data = clsApp.LoadData();
return data;
}
public static void InitTimer()
{
Timer t = new Timer();
t.Elapsed += new ElapsedEventHandler(OnTimedEvent);
t.Interval = 50000;
t.Enabled = true;
}
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
GetData();
}
}
class Program
{
static void Main()
{
List<string> data = clsSample.GetData();
}
}
I need to get the return data from GetData() method .But timer need not be called in the Main method.How is this posible?
put the following on clsSample :
public delegate void EventRaiser(List<string> data);
public event EventRaiser OnDataRetrieved;
and put this on the timer method
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
if(OnDataRetrieved !=null)
{
OnDataRetrieved(GetData())
}
}
then handle the event from the program.cs class

How to run a windows form from a backgroundworker runnig through another backgroundworker?

this is the simplified plan for a solution:
for some reasons i need to run a windows form through a backgroundworker that is runnig by another backgroundworker, when the new windows form loads, the older backgroundworker must pause. i write the code like this :
creating a class with name : temp
public class temp
{
static public BackgroundWorker backgroundWorker1 = new BackgroundWorker() { WorkerSupportsCancellation = true };
static public EventWaitHandle ew = new EventWaitHandle(false, EventResetMode.ManualReset);
static public BackgroundWorker back = new BackgroundWorker() { WorkerSupportsCancellation = true };
}
the codes for form1 are :
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
temp.backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
temp.back.DoWork += new DoWorkEventHandler(back_DoWork);
}
void back_DoWork(object sender, DoWorkEventArgs e)
{
Form2 f = new Form2();
f.Show();
}
private void button1_Click(object sender, EventArgs e)
{
temp.backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
temp.back.RunWorkerAsync();
if (temp.backgroundWorker1.CancellationPending)
temp.ew.WaitOne();
}
}
}
and the codes of form2 goes here :
namespace WindowsFormsApplication1
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
temp.backgroundWorker1.CancelAsync();
temp.ew.Reset();
}
}
}
by clicking the button1 from form1 the temp.backgroundworker1 runs and then in the DoWork of temp.backgroundworker1, the temp.back runs and then FORM2 LOADS BUT THE FORM2 HANGS AND BECOMES USELESS AND YOU CANNOT USE THAT ANY MORE.
where did i wrong ?
the whole plan that i'm going to execute is :
we have a For loop that processes every row of a DataGridView.
each time in a certain point, another windowsform opens
and it stops the loop until the user inserts the information and then click on OK button, the windowsform closes and the loop keep on working. i dont know what to do.......
even if i dont cancel working of the temp.backgroundworker in form2load like the code below, the Form2 is useless
private void Form2_Load(object sender, EventArgs e)
{
}
Do not use any UI operation in the work thread (DoWork method). Maybe that's why you set the CheckForIllegalCrossThreadCalls property, but your app will not work properly just suppresses the error when the debugger is attached.
See my answer here for the correct usage of the BackgroundWorker (that is about canceling but you can see the operations in UI and worker thread).
In this particular case what you can use a similar volatile bool to sign the UI thread that the form can be shown. Or, if you want to send different messages between the threads, use a ConcurrentQueue<T> to write and read messages:
public partial class Form1 : Form
{
private enum Message
{
ShowForm2,
SuspendWork,
ResumeWork,
FinishWorker1
// ... and whatever you want
}
private Timer timer;
private ConcurrentQueue<Message> messagesToUI = new ConcurrentQueue<Message>();
private ConcurrentQueue<Message> messagesToWorker = new ConcurrentQueue<Message>();
public Form1()
{
InitializeComponent();
timer = new Timer(this);
timer.Interval = 10;
timer.Tick += PollUIMessages;
timer.Enabled = true;
}
void PollUIMessages(object sender, EventArgs e)
{
// do we have a new message?
Message message;
if (messagesToUI.TryDequeue(out message))
{
switch (message)
{
case Message.ShowForm2:
Form2 f = new Form2();
f.Show();
// todo: in Form2.Close add a Resume message to the messagesToWorker
break;
// ... process other messages
}
}
}
void back_DoWork(object sender, DoWorkEventArgs e)
{
// Here you are in the worker thread. You can send a message to the
// UI thread like this:
messagesToUI.Enqueue(Message.ShowForm2);
bool isWorking = true;
// and here you can poll the messages to the worker thread
while (true)
{
Message message;
if (!messagesToWorker.TryDequeue(out message))
{
// no message: idle or work
if (isWorking)
DoSomeWork(); // do whatever you want
else
Thread.CurrentThread.Sleep(10);
continue;
}
switch (message)
{
case Message.FinishWorker1:
// finishing the worker: jumping out
return;
case Message.SuspendWork:
isWorking = false;
break;
case Message.ResumeWork:
isWorking = true;
break;
}
}
}

Updating GUI multithreading application

I have main program
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Worker w1 = new Worker(1);
Worker w2 = new Worker(2);
Thread w1Thread = new Thread(new ThreadStart(w1.StartWorking));
Thread w2Thread = new Thread(new ThreadStart(w2.StartWorking));
w1Thread.Start();
w2Thread.Start();
Application.Run(new MainWindow());
if (w1Thread.IsAlive)
{
w1Thread.Abort();
}
if (w2Thread.IsAlive)
{
w2Thread.Abort();
}
}
}
and worker class:
class Worker
{
public int m_workerId;
public bool m_workerLifeBit;
public bool m_workerWork;
public Worker(int id)
{
m_workerId = id;
m_workerLifeBit = false;
}
public void StartWorking()
{
while (!m_workerWork)
{
m_workerLifeBit = false;
System.Threading.Thread.Sleep(5000);
m_workerLifeBit = true;
System.Threading.Thread.Sleep(5000);
}
}
}
I have checkBox on MainWindow form.
How to monitor state of Worker variable m_workerLifeBit and display its changes in MainWindow checkBox?
I have found this q&a How to update the GUI from another thread in C#? hovewer the answer does not show complete example, and I failed with using thread safe delegate.
I want some event mechanism that I fire in Worker.StartWorking and catch in slot in MainWindow form.
Here is a simple version using events:
class Worker
{
public event Action<bool> WorkerLifeBitChanged;
// ...
public void StartWorking()
{
// ...
m_workerLifeBit = false;
OnWorkerLifeBitChanged();
// ...
private void OnWorkerLifeBitChanged()
{
if (WorkerLifeBitChanged != null)
WorkerLifeBitChanged(m_workerLifeBit);
}
Then you wire up the event in Main:
//...
var mainWindow = new MainWindow();
w1.WorkerLifeBitChanged += mainWindow.UpdateWorkerLifeBit;
w2.WorkerLifeBitChanged += mainWindow.UpdateWorkerLifeBit;
w1Thread.Start();
w2Thread.Start();
Application.Run(mainWindow);
//...
And UpdateWorkerLifeBit implementation in MainWindow:
public void UpdateWorkerLifeBit(bool workerLifeBit)
{
if (this.checkBox.InvokeRequired)
{
this.Invoke(new Action(() => checkBox.Checked = workerLifeBit));
}
else
{
checkBox.Checked = workerLifeBit;
}
}
As mentioned in the comments, if this is a WinForms application then I'd recommend using a BackgroundWorker.
Kicking off the bg worker and subscribing to events:
BackgroundWorker worker = new BackgroundWorker();
// Subscribing to the worker method. Do all of your work here
worker.DoWork += worker_DoWork;
// Subscribing to the progress changed event where you'll want to update the UI
worker.ReportProgress = true;
worker.ProgressChanged += worker_ProgressChanged;
// Subscribing to the worker completed event. Fires when the work is complete
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
// This line starts the worker
worker.RunWorkerAsync();
You would then have your methods defined as such:
void worker_DoWork(object sender, DoWorkEventArgs e)
{
// Perform some work with the object you've passed in e.g.
MyObj foo = (MyObj)e.Argument;
foo.Name = "foobar";
// Notify UI
worker.ReportProgress(100, foo);
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Update UI
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Worker has finished
}
One solution would be passing a reference of your Program class (or even a delegate in your program class, or a data reference in your worker class) to the Worker thread. You can call a function of your Program directly from the thread code then. You can also use signals, but for this small example my previous "solution" is acceptable.

Run method with BackgroundWorker on second Form

Let's imagine that we have two Forms: MainForm and WaitingForm. I want to pass, from MainForm, to the WaitingForm the method to run in background using BackgroundWorker.
Now, I'm doing things that way:
MainForm.cs:
public partial class MainForm: Form
{
private void btnImport_Click(object sender, EventArgs e)
{
var waitingFrm = new WaitingForm();
waitingFrm.DoWork = (o, args) => this.LongRunningOperation(this, new DoWorkEventArgs("foo bar"));
waitingFrm.OnWorkCompleted = (o, args) => MessageBox.Show("Finished!");
waitingFrm.Show();
waitingFrm.Run(); // should execute LongRunningOperation, method below.
}
private void LongRunningOperation(object sender, DoWorkEventArgs e)
{
MessageBox.Show("Running long operation!....");
// some long running stuff here;
}
}
WaitingForm.cs
public partial class WaitingForm: Form
{
private BackgroundWorker worker = new BackgroundWorker();
public DoWorkEventHandler DoWork { get; set; }
public RunWorkerCompletedEventHandler OnWorkCompleted { get; set; }
public WaitingForm()
{
this.worker.DoWork += DoWork;
this.worker.RunWorkerCompleted += OnWorkCompleted;
InitializeComponent();
}
public void Run()
{
this.worker.RunWorkerAsync();
}
}
But after waitingFrm.Run(); my LongRunningOperation is not executed.
In your WaitingForm I'd do:
public event DoWorkEventHandler DoWork {
add { worker.DoWork += value; }
remove { worker.DoWork += value; }
}
(Instead of the get;set; property).
And then in your main window btnImport_Click handler just:
waitingFrm.DoWork += LongRunnignOperation;
And the same for completed handler. Your syntax seems overly complicated. This is just a clean way to expose an event (in this case on your waitingform) and the pass event handler through to the real handler (in this case worker.DoWork). It is equivalent to
waitingFrm.worker.DoWork += LongRunnignOperation;
which would do just as well.
I want to pass, from MainForm, to the WaitingForm the method to run
in background using BackgroundWorker
I would in this case
declare an event in WaitingForm
before Form1 shows WaitingForm subscribes to that event
when long running operation has to be runned WaitingForm raise an event, Form1 gets it and
Form1 runs its method in other thread.
Hope this helps.
In this particular case you want all of the work to happen in MainForm and it looks like WaitingForm is just a display for the user. If that's the case then I would just put the BackgroundWorker in the MainForm and use the event to call into WaitingForm
public partial class MainForm: Form
{
private void btnImport_Click(object sender, EventArgs e) {
var waitingForm = new WaitingForm();
waitingForm.Show();
var worker = new BackgroundWorker();
worker.DoWork += (o, args) => this.LogRunningOperation(o, args);
worker.OnWorkComplete += (o, args) => {
waitingForm.Close();
worker.Dispose();
};
worker.RunWorkerAsync();
}
private void LongRunningOperation(object sender, DoWorkEventArgs e) {
MessageBox.Show("Running long operation!....");
// some long running stuff here;
}
}
So, the simple answer is that. Your code is not working because the mainform is not seeing the BackgroundWorker object instance events. Instead of doing:
this.worker.DoWork += DoWork;
this.worker.RunWorkerCompleted += OnWorkCompleted;
in WaitingForm - InitializeComponent(), do this instead in mainForm like this:
waitingFrm.worker.DoWork += waitingFrm.DoWork;
waitingFrm.worker.RunWorkerCompleted += waitingFrm.OnWorkCompleted;

Categories