How to implement dispatcher timer in class and call it - c#

So I'm working on an application that will need a timer on every page counting by the second. I figured it would be best to have the actual function on a class and have it called by the pages that need it. What I do know is how to get the timer working in a page... What baffles me is how to get it working in a class.
Needless to say, I'm failing.
Here's what I've done in the class:
namespace Masca
{
public class timer
{
public void StartTimer()
{
System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
dispatcherTimer.Start();
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
DateTime datetime = DateTime.Now;
}
And what I've done in a page I need the timer in
namespace Masca
{
public partial class signup : Elysium.Controls.Window
{
public timer timer;
public signup(string Str_Value)
{
InitializeComponent();
tag.Text = Str_Value;
}
public void dispatcherTimer_Tick(object sender, EventArgs e)
{
DateTime datetime = DateTime.Now;
this.doc.Text = datetime.ToString();
}
I can't get the 'dispatcherTimer_Tick' event to know it's supposed to get it's instructions on how to work from the class 'timer'.
Any ideas on how to do this?

You probably want to add an event to your timer class:
public class timer
{
public event EventHandler TimerTick;
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
if (TimerTick != null)
TimerTick(this, null);
}
So that in your Window you can just listen to this event.

You will need to expose either your own event or delegate from your timer class. The external classes subscribe to this event/delegate and you raise/call it from the dispatcherTimer_Tick method in your timer class.
I would do something like this in your timer class:
public delegate void TimeUp(); // define delegate
public TimeUp OnTimeUp { get; set; } // expose delegate
...
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
DateTime datetime = DateTime.Now;
if (OnTimeUp != null) OnTimeUp(); // call delegate
}
And from outside the class:
public timer timer;
...
timer.OnTimeUp += timerOnTimeUp;
private void timerOnTimeUp()
{
// time is up
}

Related

DispatcherTimer ticking not working when started in ThreadPool.QueueUserWorkItem() method

I've created a TimerManager class for my WPF application.
This class handles the start and stop the dispatcher timer.
Here is the class:
public static class TimerManager
{
static DispatcherTimer disTimer;
static Model m = Model.GetInstance();
static TimerManager()
{
disTimer = new DispatcherTimer();
disTimer.Tick += disTimer_tick;
disTimer.Interval = new TimeSpan(0, 0, 1);
}
public static void StartTimer()
{
disTimer.Start();
}
public static void StopTimer()
{
disTimer.Stop();
}
private static void disTimer_tick(object sender, EventArgs e)
{
m.Tick++;
}
}
And I've created a Model class that represents the ticking in the UI.
(Binding in MainWindow.xaml -> xy textbox text field "{Binding Tick}").
class Model : INotifyPropertyChanged
{
private Model()
{
}
static Model instance;
public static Model GetInstance()
{
if (instance == null)
{
instance = new Model();
}
return instance;
}
int tick;
public event PropertyChangedEventHandler PropertyChanged;
public void OnNotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, e);
}
}
public int Tick
{
get
{
return tick;
}
set
{
tick = value;
OnNotifyPropertyChanged();
}
}
}
And here is the MainWindow class:
Model m;
public MainWindow()
{
InitializeComponent();
m = Model.GetInstance();
this.DataContext = m;
}
private void startButton_Click(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem(o =>
{
TimerManager.StartTimer();
});
//TimerManager.StartTimer();
}
private void stopButton_Click(object sender, RoutedEventArgs e)
{
TimerManager.StopTimer();
}
When I click the start button I use the ThreadPool.QueueUserWorkItem() method. In that method, I start the timer but the timer tick is not run at every one second.
When I don't use ThreadPool this works. But this solution is not good for me; ThreadPool is important for me because I use an HTTP web server (in local).
My question is: why is the ticking not working if I use ThreadPool?
The DispatcherTimer object has thread affinity. That is, it is tied to a specific thread. In particular, it is designed specifically to raise its Tick event in the thread in which it was created, using the Dispatcher for that thread.
Your ThreadManager class's static constructor will be called when the type is first used. In your non-working example, this occurs in the queued work item method, causing the static constructor to be executed in the thread pool thread used to execute that work item method. This in turn causes the DispatcherTimer object you create to be owned by that thread, and to have its Tick event raised in that thread by the Dispatcher for that thread.
Except, thread pool threads don't have Dispatchers. So there's no Dispatcher there to raise the Tick event for the DispatcherTimer object. Even if there was, without a call to Application.Run() to have the dispatcher loop executed, the Dispatcher wouldn't actually get to dispatch anything, including the Tick event.
What you need is to make sure that when you create the DispatcherTimer object, the code that creates that object is executed in the dispatcher thread, which is your main UI thread.
There are a couple of ways to do that. IMHO, the best way is to make your ThreadManager class not a static class and to create an instance of it in your MainWindow constructor. For example:
class TimerManager
{
DispatcherTimer disTimer;
Model m = Model.GetInstance();
public TimerManager()
{
disTimer = new DispatcherTimer();
disTimer.Tick += disTimer_tick;
disTimer.Interval = new TimeSpan(0, 0, 1);
}
public void StartTimer()
{
disTimer.Start();
}
public void StopTimer()
{
disTimer.Stop();
}
private void disTimer_tick(object sender, EventArgs e)
{
m.Tick++;
}
}
and:
public partial class MainWindow : Window
{
TimerManager _timerManager = new TimerManager();
public MainWindow()
{
InitializeComponent();
this.DataContext = Model.GetInstance();
}
private void startButton_Click(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem(o =>
{
_timerManager.StartTimer();
});
}
private void stopButton_Click(object sender, RoutedEventArgs e)
{
_timerManager.StopTimer();
}
}
Since you know your MainWindow object has to be created in the dispatcher thread, and you know that non-static field initialization happens at the same time the constructor is called, in that same dispatcher thread, the above ensures that your TimerManager object is created in the dispatcher thread.
This gives you complete control over the lifetime of the TimerManager object, particularly when it's created but of course also when it can be discarded. Given the nature of the DispatcherTimer object itself, it's my opinion that this is better than maintaining a statically-held instance.
This approach also gives you the option of having a manager object for each dispatcher thread (in rare cases, a program might have more than one…you should try very hard to avoid getting into that situation, but it can be useful for types to at least be compatible with such a situation).
That said, if you really want to keep the static implementation, you can do that by providing a method that can be called explicitly when you want to initialize the class, so you can make sure that the initialization happens in the right thread:
static class TimerManager
{
static DispatcherTimer disTimer;
static Model m = Model.GetInstance();
public static void Initialize()
{
disTimer = new DispatcherTimer();
disTimer.Tick += disTimer_tick;
disTimer.Interval = new TimeSpan(0, 0, 1);
}
public static void StartTimer()
{
disTimer.Start();
}
public static void StopTimer()
{
disTimer.Stop();
}
private static void disTimer_tick(object sender, EventArgs e)
{
m.Tick++;
}
}
Then in your MainWindow class:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = Model.GetInstance();
StaticTimerManager.Initialize();
}
private void startButton_Click(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem(o =>
{
StaticTimerManager.StartTimer();
});
}
private void stopButton_Click(object sender, RoutedEventArgs e)
{
StaticTimerManager.StopTimer();
}
}
All you need to do here is make sure you call the Initialize() method from the main UI thread where you actually have a running dispatcher, before you attempt to call either of the other two static methods in the class.
This approach could also be made to work with multiple threads (i.e. if you have more than one dispatcher thread), but it would be trickier, especially if you want to be able to call the StartTimer() method from a different thread that actually owns the timer object. I'd recommend against the static class approach if you really did wind up in that situation.

C# How to raise an event to start timer from a class other than the main form?

In my main Form1, I have
int duration = 5;
public void timer1_Tick(object sender, EventArgs e)
{
duration--;
if (duration == 0)
{
timer1.Stop();
MessageBox.Show("timesup");
}
}
Elsewhere, (specifically the class I use for my UDP listener), I run an event to reference changes to the form
private MyProject.Form1 _form { get; set; }
public UDPListener(TapeReader.Form1 form)
{
_form = form;
}
Then I would try to call it when the incoming data meets my criteria
if (numberSize>paramSize)
{
if (_form.listBox1.InvokeRequired)
{
_form.listBox1.Invoke((MethodInvoker)delegate ()
{
//Below is where I would like the timer to start
_form.timer1.Start();
//This won't work as I need the timer1_Tick from the main. How can I run this from a different class other than the main form?
});
}
}
Like the other components of my form, I can reference it fine with _form but timer1_Tick is a method (void). Is there a way to do this?
Figured a solution. I just used this tutorial to help me https://msdn.microsoft.com/en-us/library/system.windows.forms.timer.tick(v=vs.110).aspx
In my other class, I have:
_form.timer1.Tick += new EventHandler(TimerEventProcessor);
and I reference it to
int duration = 5;
private void TimerEventProcessor(object myObject, EventArgs myEventArgs)
{
duration--;
if(duration==0)
{
MessageBox.Show("timesup");
}
}

Replacing the System.Timers.Timer.Elapsed event when inheriting System.Timers.Timer

I'm creating a new class so that I can make the System.Timers.Timer class fit my needs just a little bit better. I create my new class like so...
using System.Timers;
class BtElapsedEventArgs : ElapsedEventArgs
{
//My extras
}
namespace MyGreatNewTimer
{
class BetterTimer : Timer
{
}
}
Now I simply want to replace the Elapsed event that fires elsewhere.
private void TestTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//Timer has elapsed
}
I want it to produce the following...
private void TestTimer_Elapsed(object sender, BtElapsedEventArgs e)
{
//Timer has elapsed
}
How can I go about doing this?
If I understand your question correctly, you can follow How to: Publish Events that Conform to .NET Framework Guidelines (C# Programming Guide) and create your own Elapsed event and hide the original Epalsed event:
namespace MyGreatNewTimer
{
class BtElapsedEventArgs : EventArgs
{
public DateTime SignalTime { get; set; }
//Some other properties
}
class BetterTimer : Timer
{
new public event EventHandler<BtElapsedEventArgs> Elapsed;
public BetterTimer()
{
base.Elapsed += BetterTimer_Elapsed;
}
void BetterTimer_Elapsed(object sender, ElapsedEventArgs e)
{
var handler = this.Elapsed;
if(handler!=null)
{
var bte = new BtElapsedEventArgs() { SignalTime = e.SignalTime};
//Set other properties, then fire the event
handler(sender, bte);
}
}
}
}

Should I put a BackgroundWorker inside a Singleton?

I have an application that takes a Wireshark capture file and feeds it (all the containing packets) into a network adapter.
Currently my application is a big mess - countless global variables & every task opened within a seperate BackgroundWorker instance etc...
To clarify - the purpose of using BackgroundWorkers here (more specifically the DoWork, RunWorkerCompleted events and the WorkerReportsProgress property) is to prevent the packet feeding operations from freezing my UI. To stop an operation, I need access to these workes - for now, global variables are used to achieve this.
So the question is - should I place my BackgroundWorker objects inside a Singleton-type class and then call this object when necessary?
From a technical point of view is possible, after all the singleton pattern is a design pattern that restricts the instantiation of a class to one object
you can try something like this
public class BackWorkerSingleton
{
private BackgroundWorker _backgroundWorker;
private static readonly object myLock = new object();
private static BackWorkerSingleton _backWorkerSingleton = new BackWorkerSingleton();
public delegate void ReportProgressEventHandler(object sender,MyEventsArgs e);
public event ReportProgressEventHandler ReportProgress = delegate{ };
private BackWorkerSingleton()
{
_backgroundWorker = new BackgroundWorker();
_backgroundWorker.DoWork += new DoWorkEventHandler(_backgroundWorker_DoWork);
_backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(_backgroundWorker_ProgressChanged);
}
void _backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.ReportProgress( this, new MyEventsArgs(){Progress = e.ProgressPercentage});
}
void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// do your work here
}
public void StartTheJob()
{
_backgroundWorker.RunWorkerAsync();
}
public static BackWorkerSingleton Worker
{
get
{
lock (myLock)
{
if (_backWorkerSingleton == null)
{
_backWorkerSingleton = new BackWorkerSingleton();
}
}
return _backWorkerSingleton;
}
}
}
class MyEventsArgs:EventArgs
{
public int Progress { get; set; }
}
and here the report progress
private void Form1_Load(object sender, EventArgs e)
{
BackWorkerSingleton.Worker.ReportProgress += new BackWorkerSingleton.ReportProgressEventHandler(Worker_ReportProgress);
}
void Worker_ReportProgress(object sender, MyEventsArgs e)
{
}
and call it like this
BackWorkerSingleton.Worker.StartJob()

Windows Store Application Metronome Stop Button Not Working

Hello there i am developing Windows Store App.
First of all, here is my code:
public class TickArgs : EventArgs
{
public DateTime Time { get; set; }
}
public class Metronome
{
private DispatcherTimer _timer;
public event TickHandler Tick;
public delegate void TickHandler(Metronome m, TickArgs e);
public Metronome()
{
_timer = new DispatcherTimer();
_timer.Tick += Timer_Tick;
}
private void Timer_Tick(object sender, object e)
{
if (Tick != null)
{
Tick(this, new TickArgs { Time = DateTime.Now });
}
}
public void Start(int bbm)
{
_timer.Stop();
_timer.Interval = TimeSpan.FromSeconds(60 / bbm);
_timer.Start();
}
public void Stop()
{
_timer.Stop();
_timer.Start();
}
}
public class Listener
{
public void Subscribe(Metronome m, MediaElement mmx)
{
m.Tick += (mm, e) => mmx.Play();
}
public void UnSubscribe(Metronome m, MediaElement mmx)
{
m.Tick += (mm, e) => mmx.Stop();
}
}
To start metronome i use these codes:
l.Subscribe(m, mediaelement);
m.Start(120);
This works perfectly fine.
To stop metronome i use these codes:
l.UnSubscribe(m, mediaelement);
m.Stop();
Metronome stops BUT if i try to start again, it just does not start. What should i do?
I would appreciate your helps.
My regards...
Okay, so what you have done is you've subscribed your metronome to two handlers, each happening on the tick timer.
First of all, make a static method in your Listener class as the event handler that you can remove.
private static void TickPlay(object sender, EventArgs e)
{
mmx.Play();
}
Then, in your Subscribe method, just say:
m.Tick += TickPlay;
Lastly, for your Unsubscribe method, say:
m.Tick -= TickPlay;
This way it won't keep going Play/Stop ever tick interval.
I found the solution.
I've just made small changes in start and stop methods:
public void Start(int bbm)
{
_timer.Interval = new TimeSpan(0, 0, 0, 0, 500);
_timer.Start();
}
public void Stop()
{
_timer.Stop();
}
Now it works perfectly fine.
Regards

Categories

Resources