How to set System.Timers.Timer in presenter in order to elapse in view thread?
Environment: C#, .NET 4.0 CP, WinForms
My current cod is here, but it doesn't work. I have to additionally "Invoke" in the view.
I cast view to ISynchronizeInvoke to build the code. Casting to Control doesn't help.
public class GeneratorPagePresenter : IGeneratorPagePresenter
{
private IGeneratorPage view;
private Timer timer;
public void SetView(IGeneratorPage generatorPage)
{
view = generatorPage;
timer = new Timer();
timer.Interval = 1000;
timer.AutoReset = true;
timer.SynchronizingObject = (ISynchronizeInvoke) view;
timer.Elapsed += Timer_Elapsed;
}
void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
view.UpdateProgress(percentage);
}
}
EDIT
Thanks to AnPasant comment (which mysteriously disapeared). I set SynchronizingObject as a parameter. It works fine, but the code looks something strange.
public void SetView(IGeneratorPage generatorPage, ISynchronizeInvoke sync)
{
view = generatorPage;
timer = new Timer();
timer.Interval = 1000;
timer.AutoReset = true;
timer.SynchronizingObject = sync;
timer.Elapsed += Timer_Elapsed;
}
This method is called by View as follows:
presenter.SetView(this, this);
The thing is that you have to switch Synchronization Context somewhere. ViewModel in this case schould be created in UI Thread.
private IGeneratorPage view;
private Timer timer;
private SynchronizationContext uiSyncContext;
public GeneratorPagePresenter()
{
uiSyncContext = SynchronizationContext.Current;
}
public void SetView(IGeneratorPage generatorPage)
{
view = generatorPage;
timer = new Timer();
timer.Interval = 1000;
timer.AutoReset = true;
timer.Elapsed += Timer_Elapsed;
}
void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
uiSyncContext.Post((state) => view.UpdateProgress(percentage), null);
}
Related
How do I make this dispatch timer 1 line of code instead of this
private DispatcherTimer timer1;
public void InitTimer()
{
timer1 = new System.Windows.Threading.DispatcherTimer();
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = TimeSpan.FromMilliseconds(2000);
timer1.Start();
}
the x problem? it gets a null error when I uncheck it to disable it
private DispatchTimer timer1; //<- Main part of the problem?
public void InitTimer()
{
timer1 = new System.Windows.Threading.DispatcherTimer();
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = TimeSpan.FromMilliseconds(2000);
timer1.IsEnabled = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
if (AS.Vis.Visibility != Visibility.Visible == false)
{
AS.Vis.Visibility = Visibility.Hidden;
timer1.IsEnabled = false;
}
else
{
AS.Vis.Visibility = Visibility.Visible;
Comp();
}
}
private void AKS_Checked(object sender, RoutedEventArgs e)
{
InitTimer();
AS.Vis.Visibility = Visibility.Visible;
timer1.IsEnabled = true;// <-Also part of the problem
}
private void AKS_Unchecked(object sender, RoutedEventArgs e)
{
AS.Vis.Visibility = Visibility.Hidden;
timer1.IsEnabled = false; //<-The problem
}
I have tried some "work arounds" that I thought would end up working but they didn't so I came to the conclusion that if the dispatchtimer was one line of code it wouldn't cause a null error since private DispatchTimer timer1; bit of code wouldn't exist but I have been told that isn't really the problem?
Creating a new DispatcherTimer instance without stopping the recent and without unsubscribing from the DispatcherTimer.Tick event, keeps all the timers running forever and executing callbacks forever. This is what you are currently doing. Every call to AKS_Checked creates a new DispatcherTimer without stopping the running one and without cleaning up event handlers.
The following example is a refactored version of your code and guarantees that there will be only one single timer instance.
It also fixes the null-reference issue by initializing the private timer property properly.
DispatcherTimer.Start resets the timer and starts it.
partial class MainWindow : Window
{
private DispatcherTimer Timer { get; set; }
public void MainWindow()
{
InitializeComponent();
InitTimer();
}
private void InitTimer()
{
this.Timer = new System.Windows.Threading.DispatcherTimer();
this.Timer.Tick += OnTick;
this.Timer.Interval = TimeSpan.FromMilliseconds(2000);
}
private void OnTick(object sender, EventArgs e)
{
if (AS.Vis.Visibility == Visibility.Visible)
{
AS.Vis.Visibility = Visibility.Hidden;
this.Timer.Stop();
}
else
{
AS.Vis.Visibility = Visibility.Visible;
Comp();
}
}
private void AKS_Checked(object sender, RoutedEventArgs e)
{
AS.Vis.Visibility = Visibility.Visible;
// Reset and start the timer
this.Timer.Start();
}
private void AKS_Unchecked(object sender, RoutedEventArgs e)
{
AS.Vis.Visibility = Visibility.Hidden;
this.Timer.Stop();
}
}
If this is the real problem:
I just get a null reference when I try to disable the timer
Then try this, so the timer variable is initialised earlier.
private DispatchTimer timer1 = new System.Windows.Threading.DispatcherTimer();
public void InitTimer()
{
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = TimeSpan.FromMilliseconds(2000);
timer1.Start();
}
This will initialise the variable when the class is created, before InitTimer (or your disable function) can be called.
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;
I am using a timer to output text to textbox every 2 seconds. but it seems that it doesnt work. any idea what is wrong. here is my code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public static System.Timers.Timer aTimer;
public void BtnGenData_Click(object sender, EventArgs e)
{
aTimer = new System.Timers.Timer(10000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
// Set the Interval to 2 seconds (2000 milliseconds).
aTimer.Interval = 2000;
aTimer.Enabled = true;
}
public static void OnTimedEvent(object source, ElapsedEventArgs e)
{
string GenData = "Welcome";
Form1 frm1 = new Form1();
frm1.TboxData.AppendText(GenData.ToString());
}
}
Actually i dont see any output coming.
Although this is not straightly connected with the problem you have in your code, but...
From MSDN System.Timers.Timer:
The server-based Timer is designed for use with worker threads in a
multithreaded environment.
In Windows Forms you can use System.WindowsForms.Timer:
System.Windows.Forms.Timer timer;
public Form1()
{
InitializeComponent();
timer = new Timer();
timer.Interval = 1000;
timer.Tick += new EventHandler(timer_Tick);
}
public void BtnGenData_Click(object sender, EventArgs e)
{
BtnGenData.Enabled = false;
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
timer.Stop();
BtnGenData.Enabled = true;
//do what you need
}
As for your code, why make the timer static? Try to use this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public System.Timers.Timer aTimer;
public void BtnGenData_Click(object sender, EventArgs e)
{
aTimer = new System.Timers.Timer(10000);
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 2000;
aTimer.Enabled = true;
}
public void OnTimedEvent(object source, ElapsedEventArgs e)
{
this.TboxData.AppendText("Welcome");
}
}
Also you should take into consideration, what could happen if you pressed the button twice...
The problem is in this method:
public static void OnTimedEvent(object source, ElapsedEventArgs e)
{
string GenData = "Welcome";
Form1 frm1 = new Form1();
frm1.TboxData.AppendText(GenData.ToString());
}
By calling new Form1(); you create a new form. This form is created as hidden, you change the text, but it is not displayed and at the end of this method it is garbage collected. What you want is to reuse your existing one. Completely remove this line and use your existing form. By default the name should be form1
public static void OnTimedEvent(object source, ElapsedEventArgs e)
{
string GenData = "Welcome";
form1.TboxData.AppendText(GenData.ToString());
}
I'd like to change a timer interval in another thread:
class Context : ApplicationContext {
private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
public Context() {
timer.Interval = 1;
timer.Tick += timer_Tick;
timer.Start();
Thread t = new Thread(ChangeTimerTest);
t.Start();
}
private void ChangeTimerTest() {
System.Diagnostics.Debug.WriteLine("thread run");
timer.Interval = 2;
}
private void timer_Tick(object sender,EventArgs args) {
System.Diagnostics.Debug.WriteLine(System.DateTime.Now.ToLongTimeString());
}
}
But the timer stops when I change the interval in the new thread. No errors, timer just stops.
Why is this happening and how can I fix it?
thx
Try this, I tried it and it works, I only changed new interval from 2 to 2000ms so you can see the difference in the Output.
You have to change interval in a thread safe manner your interval because the timer is in UI thread context. In these cases it is recommended to use delegates.
private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
public void Context() {
timer.Interval = 1;
timer.Tick += timer_Tick;
timer.Start();
Thread t = new Thread(ChangeTimerTest);
t.Start();
}
delegate void intervalChanger();
void ChangeInterval()
{
timer.Interval = 2000;
}
void IntervalChange()
{
this.Invoke(new intervalChanger(ChangeInterval));
}
private void ChangeTimerTest() {
System.Diagnostics.Debug.WriteLine("thread run");
IntervalChange();
}
private void timer_Tick(object sender,EventArgs args) {
System.Diagnostics.Debug.WriteLine(System.DateTime.Now.ToLongTimeString());
}
In addition to my previous answer, since you are not using Forms, try to change your System.Windows.Forms.Timer to System.Timers.Timer. Note that it has Elapsed Event, not Tick. The following is the code:
System.Timers.Timer timer = new System.Timers.Timer();
public Context() {
timer.Interval = 1;
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Start();
Thread t = new Thread(ChangeTimerTest);
t.Start();
}
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
System.Diagnostics.Debug.WriteLine(System.DateTime.Now.ToLongTimeString());
}
private void ChangeTimerTest() {
System.Diagnostics.Debug.WriteLine("thread run");
timer.Interval = 2000;
}
Hope this will finally help!
Ok so I am using System.Timers.Timer in .Net 4 with C#.
I have my timer object like so:
var timer = new Timer {Interval = 123};
I have my Timer Elapsed event handler pointed at a method like so:
timer.Elapsed += MyElapsedMethod;
And my method looks like this:
static void MyElapsedMethod(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Foo Bar");
}
I want to pass a string into this method, how do I do this?
Thanks
The easiest way to do this is to change the event handler into an anonymous function. It allows you to pass the string at the point of declaration.
string theString = ...;
timer.Elapsed += (sender, e) => MyElapsedMethod(sender, e, theString);
static void MyElapsedMethod(object sender, ElapsedEventArgs e, string theString) {
...
}
If you want to be able to unregister your "Elapsed" event handler again, you shouldn't use a delegate without remembering it in a variable.
So another solution could be to create a custom class based on Timer. Just add whatever members you like and get your custom Timer object back from the "sender" argument of the "Elapsed" event handler:
class CustomTimer : System.Timers.Timer
{
public string Data;
}
private void StartTimer()
{
var timer = new CustomTimer
{
Interval = 3000,
Data = "Foo Bar"
};
timer.Elapsed += timer_Elapsed;
timer.Start();
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
string data = ((CustomTimer)sender).Data;
}
This strategy of course works for other events and classes too, as long as the base class is not sealed.
You can save string in some object and read it in event handler:
static string _value;
static void MyElapsedMethod(object sender, ElapsedEventArgs e)
{
Console.WriteLine(_value);
}
UPDATE: same code via different syntax:
timer.Elapsed += (s,e) => Console.WriteLine(_value);
UPDATE: Consider also using System.Threading.Timer instead
State state = new State();
Timer timer = new Timer(OnTimer, state, 0, 123);
state.Value = "FooBar"; // change state object
You can retrieve state in timer callback:
static void OnTimer(object obj)
{
State state = obj as State;
if (state == null)
return;
Console.WriteLine(state.Value);
}
Timer aTimer = new Timer(300);
aTimer.Elapsed += delegate { PublishGPSData(channel, locationViewModel); };
// Hook up the Elapsed event for the timer.
aTimer.AutoReset = true;
aTimer.Enabled = true;
private void PublishGPSData(IModel channel, LocationViewModel locationViewModel)
{
};
Use a field in the same class to hold whatever string you want and then retrieve it in you elapsed event handler. You'll have to be careful about cross-threading issues however.
I wrote this simple class to handle this:
using System;
using System.Timers;
namespace MyProject.Helpers
{
public class MyTimer
{
private volatile Timer _timer = new Timer();
private volatile bool _requestStop = false;
private MyElapsedEventHandler _eventHander;
private MyElapsedEventHandlerWithParam _eventHandlerWithParam;
private object _param;
public MyTimer(int interval, MyElapsedEventHandler elapsedEventHandler, bool autoReset = false)
{
_timer.Interval = interval;
_timer.Elapsed += ElapsedWrapper;
_timer.AutoReset = autoReset;
_eventHander = elapsedEventHandler;
Start();
}
public MyTimer(int interval, MyElapsedEventHandlerWithParam elapsedEventHandler, object param, bool autoReset = false)
{
_timer.Interval = interval;
_timer.Elapsed += ElapsedWrapperWithParam;
_timer.AutoReset = autoReset;
_eventHandlerWithParam = elapsedEventHandler;
_param = param;
Start();
}
private void ElapsedWrapper(object sender, ElapsedEventArgs e)
{
if (!_requestStop && _eventHander != null)
{
_eventHander();
}
}
private void ElapsedWrapperWithParam(object sender, ElapsedEventArgs e)
{
if (!_requestStop && _eventHandlerWithParam != null)
{
_eventHandlerWithParam(_param);
}
}
public void Stop()
{
_requestStop = true;
_timer.Stop();
}
public void Start()
{
_requestStop = false;
_timer.Start();
}
}
public delegate void MyElapsedEventHandlerWithParam(object param);
public delegate void MyElapsedEventHandler();
}
use it like this:
void Main(string[] args){
new MyTimer(durationInSeconds * 1000, EventHandler, "some string");
}
void EventHandler(object param){
doSomethingWithString((string)param);
}
you can also pass the event arguments or any kind of parameters if you edit the delegate (and the call of the event handler in MyTimer class).
Why not just use a Timer and an ElapsedEventHandler?
namespace TimerEventHandler
{
class Program
{
private static Timer myEventTimer;
static void Main(string[] args)
{
// 5 second timer multiply 1000 milliseconds by the time
//e.g. new Timer(60 * 1000 * 10) = 10 minutes
myEventTimer = new Timer(5 * 1000 * 1);
myEventTimer.Enabled = true;
myEventTimer.Elapsed += new ElapsedEventHandler(TimerSchedule_Elapsed);
Console.WriteLine("Timer started!");
// make a thread and wait forever just so console does not go away
Thread.Sleep(Timeout.Infinite);
}
private static void TimerSchedule_Elapsed(object sender, ElapsedEventArgs e)
{
// do something
Console.WriteLine("Timer elapsed!");
}
}
}