how to raise event with timer? - c#

ok so i have two classes each with timers set at different intervals. one goes off every 2 seconds, the other every 2 minutes. each time the code runs under the timer i want it to raise an event with the string of data the code generates. then i want to make another class that subscribes to the event args from the other classes and does something like write to console whenever an event is fired. and since one class only fires every 2 minutes this class can store the last event in a private field and reuse that every time until a new event is fired to update that value.
So, how do i raise an event with the string of data?, and how to subscribe to these events and print to screen or something?
this is what i have so far:
public class Output
{
public static void Main()
{
//do something with raised events here
}
}
//FIRST TIMER
public partial class FormWithTimer : EventArgs
{
Timer timer = new Timer();
public FormWithTimer()
{
timer = new System.Timers.Timer(200000);
timer.Elapsed += new ElapsedEventHandler(timer_Tick); // Everytime timer ticks, timer_Tick will be called
timer.Interval = (200000);
timer.Enabled = true; // Enable the timer
timer.Start(); // Start the timer
}
//Runs this code every 2 minutes, for now i just have it running the method
//(CheckMail();) of the code but i can easily modify it so it runs the code directly.
void timer_Tick(object sender, EventArgs e)
{
CheckMail();
}
public static string CheckMail()
{
string result = "0";
try
{
var url = #"https://gmail.google.com/gmail/feed/atom";
var USER = "usr";
var PASS = "pss";
var encoded = TextToBase64(USER + ":" + PASS);
var myWebRequest = HttpWebRequest.Create(url);
myWebRequest.Method = "POST";
myWebRequest.ContentLength = 0;
myWebRequest.Headers.Add("Authorization", "Basic " + encoded);
var response = myWebRequest.GetResponse();
var stream = response.GetResponseStream();
XmlReader reader = XmlReader.Create(stream);
System.Text.StringBuilder gml = new System.Text.StringBuilder();
while (reader.Read())
if (reader.NodeType == XmlNodeType.Element)
if (reader.Name == "fullcount")
{
gml.Append(reader.ReadElementContentAsString()).Append(",");
}
Console.WriteLine(gml.ToString());
// I want to raise the string gml in an event
}
catch (Exception ee) { Console.WriteLine(ee.Message); }
return result;
}
public static string TextToBase64(string sAscii)
{
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] bytes = encoding.GetBytes(sAscii);
return System.Convert.ToBase64String(bytes, 0, bytes.Length);
}
}
//SECOND TIMER
public partial class FormWithTimer2 : EventArgs
{
Timer timer = new Timer();
public FormWithTimer2()
{
timer = new System.Timers.Timer(2000);
timer.Elapsed += new ElapsedEventHandler(timer_Tick); // Everytime timer ticks, timer_Tick will be called
timer.Interval = (2000); // Timer will tick evert 10 seconds
timer.Enabled = true; // Enable the timer
timer.Start(); // Start the timer
}
//Runs this code every 2 seconds
void timer_Tick(object sender, EventArgs e)
{
using (var file = MemoryMappedFile.OpenExisting("AIDA64_SensorValues"))
{
using (var readerz = file.CreateViewAccessor(0, 0))
{
var bytes = new byte[194];
var encoding = Encoding.ASCII;
readerz.ReadArray<byte>(0, bytes, 0, bytes.Length);
//File.WriteAllText("C:\\myFile.txt", encoding.GetString(bytes));
StringReader stringz = new StringReader(encoding.GetString(bytes));
var readerSettings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment };
using (var reader = XmlReader.Create(stringz, readerSettings))
{
System.Text.StringBuilder aida = new System.Text.StringBuilder();
while (reader.Read())
{
using (var fragmentReader = reader.ReadSubtree())
{
if (fragmentReader.Read())
{
reader.ReadToFollowing("value");
//Console.WriteLine(reader.ReadElementContentAsString() + ",");
aida.Append(reader.ReadElementContentAsString()).Append(",");
}
}
}
Console.WriteLine(aida.ToString());
// I want to raise the string aida in an event
}
}
}
}

First, I would make a base class that has handles the logic relating to the event. Here is an example:
/// <summary>
/// Inherit from this class and you will get an event that people can subsribe
/// to plus an easy way to raise that event.
/// </summary>
public abstract class BaseClassThatCanRaiseEvent
{
/// <summary>
/// This is a custom EventArgs class that exposes a string value
/// </summary>
public class StringEventArgs : EventArgs
{
public StringEventArgs(string value)
{
Value = value;
}
public string Value { get; private set; }
}
//The event itself that people can subscribe to
public event EventHandler<StringEventArgs> NewStringAvailable;
/// <summary>
/// Helper method that raises the event with the given string
/// </summary>
protected void RaiseEvent(string value)
{
var e = NewStringAvailable;
if(e != null)
e(this, new StringEventArgs(value));
}
}
That class declares a custom EventArgs class to expose the string value and a helper method for raising the event. Once you update your timers to inherit from that class, you'll be able to do something like:
RaiseEvent(aida.ToString());
You can subscribe to these events like any other event in .Net:
public static void Main()
{
var timer1 = new FormWithTimer();
var timer2 = new FormWithTimer2();
timer1.NewStringAvailable += new EventHandler<BaseClassThatCanRaiseEvent.StringEventArgs>(timer1_NewStringAvailable);
//Same for timer2
}
static void timer1_NewStringAvailable(object sender, BaseClassThatCanRaiseEvent.StringEventArgs e)
{
var theString = e.Value;
//To something with 'theString' that came from timer 1
Console.WriteLine("Just got: " + theString);
}

Related

how do I set the name of a system.timer dynamically

I have to create several timers dynamically but I need the name of them when they fire.
Here is my code:
timersDict = new Dictionary<string, System.Timers.Timer>();
int i = 0;
foreach (var msg in _messages.CurrentMessages)
{
var timer = new System.Timers.Timer();
timer.Interval = int.Parse(msg.Seconds);
timer.Elapsed += Main_Tick;
timer.Site.Name = i.ToString();
i++;
}
I thought I could set it from timer.Site.Name but I get a null exception on Site.
How do I set the name of the timer I am creating?
EDIT
I am creating this since I need to know what timer is firing when it gets to the elapsed event. I have to know what message to display once it fires.
Can I pass the message with the timer and have it display the message based on what timer it is?
Here is the rest of my code:
void Main_Tick(object sender, EventArgs e)
{
var index = int.Parse(((System.Timers.Timer)sender).Site.Name);
SubmitInput(_messages.CurrentMessages[index].MessageString);
}
I was going to use it's name to tell me which timer it was so I know what message to display since all of the timers are created dynamically.
I'd recommend wrapping the System.Timers.Timer class and add your own name field.
Here is an example:
using System;
using System.Collections.Generic;
using System.Threading;
namespace StackOverFlowConsole3
{
public class NamedTimer : System.Timers.Timer
{
public readonly string name;
public NamedTimer(string name)
{
this.name = name;
}
}
class Program
{
static void Main()
{
for (int i = 1; i <= 10; i++)
{
var timer = new NamedTimer(i.ToString());
timer.Interval = i * 1000;
timer.Elapsed += Main_Tick;
timer.AutoReset = false;
timer.Start();
}
Thread.Sleep(11000);
}
static void Main_Tick(object sender, EventArgs args)
{
NamedTimer timer = sender as NamedTimer;
Console.WriteLine(timer.name);
}
}
}

Notify multiple background workers with a property change C#

I have a global variable called:
string tweet;
I run several background workers, that does nothing but wait on value change of the tweet variable. Then run a function called: ProcessTweet( object sender, MyCustomEventArgs args )
My question is what is the best way to handle the property changed event from all those background workers, and later process the results based on the tweet value and another argument passed to the ProcessTweet function.
I tried to take a look at INotifyPropertyChanged but I am not sure how to handle OnValueChange event from each background worker. Will it run the same ProcessTweet function once or each background worker will run an instance of that function?
EDIT:
private ITweet _LastTweet;
public ITweet LastTweet
{
get { return this._LastTweet; }
set
{
this._LastTweet = value;
}
}
Still not sure how to handle property change event the best way ^
And below is the rest of the code
private void bgworker_DoWork(object sender, DoWorkEventArgs e)
{
MyCustomClass myCustomClass = e.Argument as MyCustomClass;
//here I want to listen on the LastTweet Value Change event and handle it
}
List<BackgroundWorker> listOfBGWorkers = new List<BackgroundWorker>();
private BackgroundWorker CreateBackgroundWorker()
{
BackgroundWorker bgworker = new BackgroundWorker();
//add the DoWork etc..
bgworker.DoWork += new System.ComponentModel.DoWorkEventHandler(bgworker_DoWork);
return bgworker;
}
private void buttonStart_Click(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
//Create the background workers
var bgworker = CreateBackgroundWorker();
listOfBGWorkers.Add(bgworker);
//get the MYCustomClass value;
var myCustomClass = SomeFunction();
bgworker.RunWorkerAsync(myCustomClass);
}
}
Ok - here's a small console app that demonstrates what I think you're trying to do.
It creates a 'source of tweets' in a thread.
You can subscribe to this 'source' and be notified when a new tweet 'arrives'.
You create TweetHandlers which have internal queues of tweets to process
You subscribe these TweetHandlers to the source
When a new tweet arrives, it is added to the queues of all the TweetHandlers by the event subscription
The TweetHandlers are set to run in their own Tasks. Each TweetHandler has its own delegate for performing a customizable action on a Tweet.
The code is as follows:
interface ITweet
{
object someData { get; }
}
class Tweet : ITweet
{
public object someData { get; set; }
}
class TweetSource
{
public event Action<ITweet> NewTweetEvent = delegate { };
private Task tweetSourceTask;
public void Start()
{
tweetSourceTask = new TaskFactory().StartNew(createTweetsForever);
}
private void createTweetsForever()
{
while (true)
{
Thread.Sleep(1000);
var tweet = new Tweet{ someData = Guid.NewGuid().ToString() };
NewTweetEvent(tweet);
}
}
}
class TweetHandler
{
public TweetHandler(Action<ITweet> handleTweet)
{
HandleTweet = handleTweet;
}
public void AddTweetToQueue(ITweet tweet)
{
queueOfTweets.Add(tweet);
}
public void HandleTweets(CancellationToken token)
{
ITweet item;
while (queueOfTweets.TryTake(out item, -1, token))
{
HandleTweet(item);
}
}
private BlockingCollection<ITweet> queueOfTweets = new BlockingCollection<ITweet>();
private Action<ITweet> HandleTweet;
}
class Program
{
static void Main(string[] args)
{
var handler1 = new TweetHandler(TweetHandleMethod1);
var handler2 = new TweetHandler(TweetHandleMethod2);
var source = new TweetSource();
source.NewTweetEvent += handler1.AddTweetToQueue;
source.NewTweetEvent += handler2.AddTweetToQueue;
// start up the task threads (2 of them)!
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
var taskFactory = new TaskFactory(token);
var task1 = taskFactory.StartNew(() => handler1.HandleTweets(token));
var task2 = taskFactory.StartNew(() => handler2.HandleTweets(token));
// fire up the source
source.Start();
Thread.Sleep(10000);
tokenSource.Cancel();
}
static void TweetHandleMethod1(ITweet tweet)
{
Console.WriteLine("Did action 1 on tweet {0}", tweet.someData);
}
static void TweetHandleMethod2(ITweet tweet)
{
Console.WriteLine("Did action 2 on tweet {0}", tweet.someData);
}
}
The output looks like this:
Did action 2 on tweet 892dd6c1-392c-4dad-8708-ca8c6e180907
Did action 1 on tweet 892dd6c1-392c-4dad-8708-ca8c6e180907
Did action 2 on tweet 8bf97417-5511-4301-86db-3ff561d53f49
Did action 1 on tweet 8bf97417-5511-4301-86db-3ff561d53f49
Did action 2 on tweet 9c902b1f-cfab-4839-8bb0-cc21dfa301d5

Watch a variable from another thread?

I have a C# library, inside which there is a timer that keeps checking a boolean variable ProcessFinished. ProcessFinished is initialized as false.
What I want is that the main application needs to watch the variable Status from the library, and a message box should display once this ProcessFinished becomes true.
The problem I had is the message box never display if I simple execute the main application, but it displays if I step in the main application.
Here is the timer_tick code in main application:
public Window1()
{
_fl = new FijiLauncherControl();
this._statusTimer = new System.Windows.Forms.Timer(); // read log 4 times per sec
this._statusTimer.Interval = 125;
this._statusTimer.Tick += new EventHandler(_statusTimer_Tick);
InitializeComponent();
}
void _statusTimer_Tick(object sender, EventArgs e)
{
try
{
if (_fl.ProcessFinished)
{
System.Windows.MessageBox.Show("Process is finished");
_statusTimer.Stop();
}
}
catch (Exception ex)
{
}
}
private void FijiLaucherButton_Click(object sender, RoutedEventArgs e)
{
_statusTimer.Start();
_fl.LaunchFiji();
}
where the _fl is the object of the class from the other library.
Inside the library, the timer code is like this:
public FijiLauncherControl()
{
_ijmFile = "";
_fijiExeFile = "";
_logFile = "";
_outputDir = "";
_isLogOn = false;
_processOn = false;
_processFinished = false;
_headless = true;
_doneStr = "Procedure is finished.";
_logFileCheckTimer = new System.Timers.Timer(500); // read log 4 times per sec
_logFileCheckTimer.Enabled = true;
_logFileCheckTimer.Elapsed += new System.Timers.ElapsedEventHandler(_logFileCheckTimer_Elapsed);
}
void _logFileCheckTimer_Elapsed(object sender, EventArgs e)
{
if (_processOn && IsLogOn)
{
try
{
_processFinished = CheckStatuts();
}
catch (Exception ex)
{
}
}
}
I am wondering what is going on here? Is there anyway I can see the message box shows up without stepping in? What is the right way to watch ProcessFinished from the main application?
Would it not be better to fire an event from the thread and catch it. Then show the message box?
Like this maybe?
using System;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click( object sender, EventArgs e )
{
var logChecker = new LogChecker();
logChecker.FinishedExvent += () => MessageBox.Show( "Finished" );
logChecker.Start();
}
}
internal class LogChecker
{
public void Start()
{
var thread = new Thread( CheckLog );
thread.Start();
}
private void CheckLog()
{
var progress = 0;
while ( progress < 3000 )
{
Thread.Sleep( 250 );
progress += 250;
}
FinishedExvent();
}
public event TestEventHandler FinishedExvent;
}
internal delegate void TestEventHandler();
}
Try
volatile bool _processFinished;

Calling a timer tick event from Windows Form Application from another class with no GUI

I'm trying to run the timer tick event which initially runs on my windows form,also when loaded on another class using a thread. I tried calling the timer event on another thread it didn't help. Am I supposed to use the same timer or create a new timer for that thread. This is my current implementation:
namespace XT_3_Sample_Application
{
public partial class Form1 : Form
{
Queue<string> receivedDataList = new Queue<string>();
System.Timers.Timer tmrTcpPolling = new System.Timers.Timer();
public Form1()
{
InitializeComponent();
TM702_G2_Connection_Initialization();
}
static void threadcal()
{
Class1 c = new Class1();
c.timer_start();
c.test("192.168.1.188",9999);
}
public string Connection_Connect(string TCP_IP_Address, int TCP_Port_Number)
{
if (tcpClient.Connected)
{
Socket_Client = tcpClient.Client;
TcpStreamReader_Client = new StreamReader(tcpClient.GetStream(), Encoding.ASCII);
tmrTcpPolling.Start();
Status = "Connected\r\n";
}
else
{
Status = "Cannot Connect\r\n";
}
}
public string Connection_Disconnect()
{
tmrTcpPolling.Stop();
// do something
return "Disconnected\r\n";
}
void TM702_G2_Connection_Initialization()
{
tmrTcpPolling.Interval = 1;
tmrTcpPolling.Elapsed += new ElapsedEventHandler(tmrTcpPolling_Elapsed);
}
#region Timer Event
void tmrTcpPolling_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
if (tcpClient.Available > 0)
{
receivedDataList.Enqueue(TcpStreamReader_Client.ReadLine());
}
}
catch (Exception)
{
//throw;
}
}
private void tmrDisplay_Tick(object sender, EventArgs e)
{
Tick();
}
public void Tick()
{
Console.Write("tick" + Environment.NewLine);
if (receivedDataList.Count > 0)
{
string RAW_Str = receivedDataList.Dequeue();
//tbxConsoleOutput.AppendText(RAW_Str + Environment.NewLine);
tbxConsoleOutput.AppendText(Parser_Selection(RAW_Str) + Environment.NewLine);
}
}
#endregion
private void btnConnect_Click(object sender, EventArgs e)
{
tbxConsoleOutput.AppendText(Connection_Connect(tbxTCPIP.Text, Convert.ToInt32(tbxPort.Text, 10)));
Thread t = new Thread(threadcal);
t.Start();
}
}
}
But the timer tick event starts the moment the application is launched but not on button click - private void btnConnect_Click(object sender, EventArgs e).
I'm trying to call a separate thread for the class Class1's test method. I'm trying to use a similar timer event to receive output from the server, for this thread.
namespace XT_3_Sample_Application
{
class Class1
{
TcpClient tcpClient;
Socket Socket_Client;
StreamReader TcpStreamReader_Client; // Read in ASCII
Queue<string> receivedDataList = new Queue<string>();
System.Timers.Timer tmrTcpPolling = new System.Timers.Timer();
void TM702_G2_Connection_Initialization()
{
tmrTcpPolling.Interval = 1;
tmrTcpPolling.Elapsed += new ElapsedEventHandler(tmrTcpPolling_Elapsed);
}
public void test(string TCP_IP_Address, int TCP_Port_Number)
{
TM702_G2_Connection_Initialization();
try
{
string Status = "";
Ping pingSender = new Ping();
PingOptions options = new PingOptions();
PingReply reply = pingSender.Send(TCP_IP_Address, timeout, buffer, options);
if (reply.Status == IPStatus.Success)
{
tcpClient = new TcpClient();
tcpClient.Connect(TCP_IP_Address, TCP_Port_Number);
if (tcpClient.Connected)
{
Socket_Client = tcpClient.Client;
TcpStreamReader_Client = new StreamReader(tcpClient.GetStream(), Encoding.ASCII);
tmrTcpPolling.Start();
Status = "Connected\r\n";
}
else
{
Status = "Cannot Connect\r\n";
}
}
else
{
Status = "Ping Fail\r\n";
}
MessageBox.Show(TCP_IP_Address + " :" + Status);
}
catch (System.Exception ex)
{
MessageBox.Show(TCP_IP_Address + " :" + ex.Message);
}
setFilterType();
setButtonRadioLvl();
heloCmd();
}
public void timer_Start()
{
Form1 f = new Form1();
f.Tick();
}
}
}
When tried the above method the timer is not fired on the new thread. Any suggestions on this?
Without any blocking code or loop your thread will not live long. the following calls your test method every one second and doesn't use timer
static void threadcal()
{
while (true)
{
Thread.Sleep(1000);
Class1 c = new Class1();
c.test("192.168.1.188", 9999);
}
}

Alarm clock application in .Net

I'm not really writing an alarm clock application, but it will help to illustrate my question.
Let's say that I have a method in my application, and I want this method to be called every hour on the hour (e.g. at 7:00 PM, 8:00 PM, 9:00 PM etc.). I could create a Timer and set its Interval to 3600000, but eventually this would drift out of sync with the system clock. Or I could use a while() loop with Thread.Sleep(n) to periodically check the system time and call the method when the desired time is reached, but I don't like this either (Thread.Sleep(n) is a big code smell for me).
What I'm looking for is some method in .Net that lets me pass in a future DateTime object and a method delegate or event handler, but I haven't been able to find any such thing. I suspect there's a method in the Win32 API that does this, but I haven't been able to find that, either.
Or, you could create a timer with an interval of 1 second and check the current time every second until the event time is reached, if so, you raise your event.
You can make a simple wrapper for that :
public class AlarmClock
{
public AlarmClock(DateTime alarmTime)
{
this.alarmTime = alarmTime;
timer = new Timer();
timer.Elapsed += timer_Elapsed;
timer.Interval = 1000;
timer.Start();
enabled = true;
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if(enabled && DateTime.Now > alarmTime)
{
enabled = false;
OnAlarm();
timer.Stop();
}
}
protected virtual void OnAlarm()
{
if(alarmEvent != null)
alarmEvent(this, EventArgs.Empty);
}
public event EventHandler Alarm
{
add { alarmEvent += value; }
remove { alarmEvent -= value; }
}
private EventHandler alarmEvent;
private Timer timer;
private DateTime alarmTime;
private bool enabled;
}
Usage:
AlarmClock clock = new AlarmClock(someFutureTime);
clock.Alarm += (sender, e) => MessageBox.Show("Wake up!");
Please note the code above is very sketchy and not thread safe.
Interesting, I've actually come across a very similar issue and went looking for a method in the .Net framework that would handle this scenario. In the end, we ended up implementing our own solution that was a variation on a while loop w/ Thread.Sleep(n) where n gets smaller the closer you get to the desired target time (logarithmically actually, but with some reasonable thresholds so you're not maxing the cpu when you get close to the target time.) Here's a really simple implementation that just sleeps half the time between now and the target time.
class Program
{
static void Main(string[] args)
{
SleepToTarget Temp = new SleepToTarget(DateTime.Now.AddSeconds(30),Done);
Temp.Start();
Console.ReadLine();
}
static void Done()
{
Console.WriteLine("Done");
}
}
class SleepToTarget
{
private DateTime TargetTime;
private Action MyAction;
private const int MinSleepMilliseconds = 250;
public SleepToTarget(DateTime TargetTime,Action MyAction)
{
this.TargetTime = TargetTime;
this.MyAction = MyAction;
}
public void Start()
{
new Thread(new ThreadStart(ProcessTimer)).Start();
}
private void ProcessTimer()
{
DateTime Now = DateTime.Now;
while (Now < TargetTime)
{
int SleepMilliseconds = (int) Math.Round((TargetTime - Now).TotalMilliseconds / 2);
Console.WriteLine(SleepMilliseconds);
Thread.Sleep(SleepMilliseconds > MinSleepMilliseconds ? SleepMilliseconds : MinSleepMilliseconds);
Now = DateTime.Now;
}
MyAction();
}
}
You could simply reset the timer duration each time it fires, like this:
// using System.Timers;
private void myMethod()
{
var timer = new Timer {
AutoReset = false, Interval = getMillisecondsToNextAlarm() };
timer.Elapsed += (src, args) =>
{
// Do timer handling here.
timer.Interval = getMillisecondsToNextAlarm();
timer.Start();
};
timer.Start();
}
private double getMillisecondsToNextAlarm()
{
// This is an example of making the alarm go off at every "o'clock"
var now = DateTime.Now;
var inOneHour = now.AddHours(1.0);
var roundedNextHour = new DateTime(
inOneHour.Year, inOneHour.Month, inOneHour.Day, inOneHour.Hour, 0, 0);
return (roundedNextHour - now).TotalMilliseconds;
}
You could create an Alarm class which has a dedicated thread which goes to sleep until the specified time, but this will use the Thread.Sleep method. Something like:
/// <summary>
/// Alarm Class
/// </summary>
public class Alarm
{
private TimeSpan wakeupTime;
public Alarm(TimeSpan WakeUpTime)
{
this.wakeupTime = WakeUpTime;
System.Threading.Thread t = new System.Threading.Thread(TimerThread) { IsBackground = true, Name = "Alarm" };
t.Start();
}
/// <summary>
/// Alarm Event
/// </summary>
public event EventHandler AlarmEvent = delegate { };
private void TimerThread()
{
DateTime nextWakeUp = DateTime.Today + wakeupTime;
if (nextWakeUp < DateTime.Now) nextWakeUp = nextWakeUp.AddDays(1.0);
while (true)
{
TimeSpan ts = nextWakeUp.Subtract(DateTime.Now);
System.Threading.Thread.Sleep((int)ts.TotalMilliseconds);
try { AlarmEvent(this, EventArgs.Empty); }
catch { }
nextWakeUp = nextWakeUp.AddDays(1.0);
}
}
}
I know it's a bit of an old question, but I came across this when I was looking for an answer to something else. I thought I'd throw my two cents in here, since I recently had this particular issue.
Another thing you can do is schedule the method like so:
/// Schedule the given action for the given time.
public async void ScheduleAction ( Action action , DateTime ExecutionTime )
{
try
{
await Task.Delay ( ( int ) ExecutionTime.Subtract ( DateTime.Now ).TotalMilliseconds );
action ( );
}
catch ( Exception )
{
// Something went wrong
}
}
Bearing in mind it can only wait up to the maximum value of int 32 (somewhere around a month), it should work for your purposes. Usage:
void MethodToRun ( )
{
Console.WriteLine ("Hello, World!");
}
void CallingMethod ( )
{
var NextRunTime = DateTime.Now.AddHours(1);
ScheduleAction ( MethodToRun, NextRunTime );
}
And you should have a console message in an hour.
What about System.Timers.Timer class ? See http://msdn.microsoft.com/en-us/library/system.timers.timer.aspx
I have used this before with great success:
Vb.net:
Imports System.Threading
Public Class AlarmClock
Public startTime As Integer = TimeOfDay.Hour
Public interval As Integer = 1
Public Event SoundAlarm()
Public Sub CheckTime()
While TimeOfDay.Hour < startTime + interval
Application.DoEvents()
End While
RaiseEvent SoundAlarm()
End Sub
Public Sub StartClock()
Dim clockthread As Thread = New Thread(AddressOf CheckTime)
clockthread.Start()
End Sub
End Class
C#:
using System.Threading;
public class AlarmClock
{
public int startTime = TimeOfDay.Hour;
public int interval = 1;
public event SoundAlarmEventHandler SoundAlarm;
public delegate void SoundAlarmEventHandler();
public void CheckTime()
{
while (TimeOfDay.Hour < startTime + interval) {
Application.DoEvents();
}
if (SoundAlarm != null) {
SoundAlarm();
}
}
public void StartClock()
{
Thread clockthread = new Thread(CheckTime);
clockthread.Start();
}
}
I don't know if the c# works, but the vb works just fine.
Usage in VB:
Dim clock As New AlarmClock
clock.interval = 1 'Interval is in hours, could easily convert to anything else
clock.StartClock()
Then, just add an event handler for the SoundAlarm event.

Categories