I am trying to implement a timer as per the below code. I want to pass a parameter to the timer event. I have used below anonymous function approach.
However this would only pass only the first parameter to the OnTimerElapsedEvent. Can someone please advise?
class Program
{
static void Main(string[] args)
{
ClassA obj = new ClassA();
Console.WriteLine("Start" + " " + System.DateTime.Now);
obj.SampleMethod("hello", 3000);
Thread.Sleep(4000);
obj.SampleMethod("world", 6000);
Console.ReadKey();
}
}
class ClassA
{
private System.Timers.Timer tTimer;
public void SampleMethod(string strParam, int iTimerInterval)
{
if (tTimer == null)
{
tTimer = new System.Timers.Timer();
tTimer.Elapsed += (sender, e) =>
OnTimerElapsedEvent(sender, e, strParam);
}
tTimer.Interval = iTimerInterval;
tTimer.Enabled = true;
tTimer.Start();
}
private void OnTimerElapsedEvent(object source, ElapsedEventArgs e, string strParam)
{
//use strParam value here
Console.WriteLine(strParam + " " + System.DateTime.Now);
if (strParam == "world")
{
tTimer.Stop();
tTimer.Enabled = false;
}
}
}
You can inherit the Timer class to provide a parameter in the constructor like below. Or you can inherit the Timer class and provide a property:
[TestClass]
public class TimerTester
{
[TestMethod]
public void TestYourTimer()
{
var timer1 = new TimerWithParameter("param1");
timer1.Interval = 1000;
timer1.ElapsedEvent += Timer_ElapsedEvent;
timer1.Start();
var timer2 = new TimerWithParameter("param2");
timer2.Interval = 1300;
timer2.ElapsedEvent += Timer_ElapsedEvent;
timer2.Start();
Thread.Sleep(5000);
}
private void Timer_ElapsedEvent(object source, ElapsedEventArgs e, string strParam)
{
Debug.WriteLine(strParam);
}
}
public delegate void ElapsedWithParameterDelegate(object source, ElapsedEventArgs e, string strParam);
public class TimerWithParameter:Timer
{
private readonly string _strParam;
public event ElapsedWithParameterDelegate ElapsedEvent;
public TimerWithParameter(string strParam)
{
_strParam = strParam;
this.Elapsed += TimerWithParameter_Elapsed;
}
private void TimerWithParameter_Elapsed(object sender, ElapsedEventArgs e)
{
ElapsedEvent?.Invoke(this, e, _strParam);
}
}
Related
How can I factor those two function/delegate into one general function and delegate ?
Is there an easy way to do this ?
public TabControl tab;
public Label devlog;
delegate void tabHandlerCallback(bool e);
public void tabHandler(bool e)
{
if (tab.InvokeRequired)
{
tab.Invoke(new tabHandlerCallback(tabHandler), new object[] { e });
}
else
{
tab.Enabled = e;
}
}
delegate void devHandlerCallback(string e);
public void devHandler(string e)
{
if (devlog.InvokeRequired)
{
devlog.Invoke(new devHandlerCallback(devHandler), new object[] { e });
}
else
{
devlog.Text = e;
}
}
you can use following code
public delegate void InvokeDelegate();
//T_Elapsed is a thread and controls required invoke
private void T_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
this.BeginInvoke(new InvokeDelegate(InvokeMethodLabel));
this.BeginInvoke(new InvokeDelegate(InvokeMethodProgressBar));
}
void InvokeMethodLabel()
{
myLabel.Text = "Test Label";
}
void InvokeMethodProgressBar()
{
progressBar.Value = (int)(progressBar.Value * 2);
}
Here is how I did it :
delegate void controlHandlerCallback(object control, object param, string field = "Text");
public void controlHandler(object control, object param, string field="Text")
{
if (((Control)control).InvokeRequired)
{
((Control)control).Invoke(new controlHandlerCallback(controlHandler), new object[] { control, param,field });
}
else
{
PropertyInfo propertyInfo = control.GetType().GetProperty(field);
propertyInfo?.SetValue(control, param);
}
}
You can make a function that can run the necessary code either directly, or by invoking.
private void InvokeIfNecessary(Control control, Action action)
{
if(control.InvokeRequired)
control.Invoke(action);
else
action();
}
// use it like this
public void devHandler(string e)
{
InvokeIfNecessary(() => devlog.Text = e);
}
public void tabHandler(bool e)
{
InvokeIfNecessary(() => tab.Enabled = e);
}
I have WinForms App where I am using the code in this following Post to check the InActivity Status of my app (Please see the accepted answer in the post). InActivity In WinForms. Once the app reaches inactivity its stopping the inactivity monitor. But then I want to restart the time once the user logs in.
So I have a notification mechanism when the user logs in and I am calling the start timer method again. I get the Started Monitor Message but the app never tracks inactivity and I don't get Timer reporting app is InACTIVE message at all. Please help.
public static System.Windows.Forms.Timer IdleTimer =null;
static int MilliSeconds = 60000;
static void Main(string[] args)
{
f = new GeneStudyForm(true, arguments.SystemTimeOutFolder, arguments.SystemTimeOutFile, StartInActivityMonitor);
int x = StartInActivityMonitor();
}
public static void StartInActivityMonitor()
{
IdleTimer = new Timer();
LeaveIdleMessageFilter limf = new LeaveIdleMessageFilter();
Application.AddMessageFilter(limf);
IdleTimer.Interval = MilliSeconds; //One minute; change as needed
Application.Idle += new EventHandler(Application_Idle);
if (IdleTimer != null)
{
MessageBox.Show(IdleTimer.Interval.ToString());
}
IdleTimer.Tick += TimeDone;
IdleTimer.Tag = InActivityTimer.Started;
MessageBox.Show("starting");
IdleTimer.Start();
}
static private void Application_Idle(object sender, EventArgs e)
{
if (!IdleTimer.Enabled) // not yet idling?
IdleTimer.Start();
}
static private void TimeDone(object sender, EventArgs e)
{
try
{
MessageBox.Show("Stopped");
IdleTimer.Stop(); // not really necessary
f.MonitorDirectory();
f.UpdateInActivityStatus();
IdleTimer.Tick -= TimeDone;
Application.Idle -= new EventHandler(Application_Idle);
}
catch(Exception ex)
{
MessageBox.Show(ex.InnerException + ex.Data.ToString());
}
}
Here is my GeneStudyForm
public partial class GeneStudyForm
{
GeneStudySystemTimeOutIO GeneStudyIO;
Func<int> StartTimer;
//Passing the StartInActivityMonitor Method as Func Delegate
public GeneStudyForm(bool isStandalone, string TimeOutFolder, string TimeOutFile, System.Func<int> MyMethod)
{
GeneStudyIO = GeneStudySystemTimeOutIO.GetInstance(TimeOutFolder, TimeOutFile);
UpdateActivityStatus(AppName.GeneStudyStatus, ActivityStatus.Active);
this.StartTimer = MyMethod;
}
public void UpdateActivityStatus(AppName name, ActivityStatus status)
{
if (GeneStudyIO != null)
{
GeneStudyIO.WriteToFile(name, status);
}
}
public void MonitorDirectory()
{
FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(GeneStudyIO.GetDriectory());
fileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;
fileSystemWatcher.Filter = "*.json";
fileSystemWatcher.Changed += FileSystemWatcher_Changed;
fileSystemWatcher.EnableRaisingEvents = true;
}
public void UnRegister(FileSystemWatcher fileSystemWatcher)
{
fileSystemWatcher.Changed -= FileSystemWatcher_Changed;
}
// I am writing the inactive status to a file. So this event will fill
private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
try
{
var root = GeneStudyIO.GetDesrializedJson();
if (root != null && root.AllApplications != null)
{
var item = root.AllApplications.Any(x => x.Status == ActivityStatus.Active.ToString());
if (!item)
{
if (InActivecount == 0)
{
GeneStudyAndApplicationCommon.TimeStatus = InActivityTimer.Ended;
MessageBox.Show("I am hiding");
this.Hide();
InActivecount++;
}
}
else
{
if (GeneStudyAndApplicationCommon.TimeStatus == InActivityTimer.Ended)
{
MessageBox.Show("I am showing");
this.Show();
UnRegister(sender as FileSystemWatcher);
UpdateActivityStatus(AppName.GeneStudyStatus, ActivityStatus.Active);
MessageBox.Show("Updated Status");
if (StartTimer != null)
{
MessageBox.Show("Starting Timer again");
if (StartTimer() == -1)
{
MessageBox.Show("Couldn't start timer");
}
}
}
}
}
}
catch (Exception ex)
{
SystemDebugLogLogger.LogException(ex);
}
}
}
This soulution is quite different from what I have posted. But I could solve my problem with this. But I want to post it if it helps someone. Here is the post I am following Last User Input
I created a class called IdleCheck where I am getting LastUserInput as follows
public static class IdleCheck
{
[StructLayout(LayoutKind.Sequential)]
private struct LASTINPUTINFO
{
[MarshalAs(UnmanagedType.U4)]
public int cbSize;
[MarshalAs(UnmanagedType.U4)]
public int dwTime;
}
[DllImport("user32.dll")]
private static extern bool GetLastInputInfo(ref LASTINPUTINFO x);
public static int GetLastInputTime()
{
var inf = new LASTINPUTINFO();
inf.cbSize = Marshal.SizeOf(inf);
inf.dwTime = 0;
return (GetLastInputInfo(ref inf)) ? Environment.TickCount - inf.dwTime : 0;
}
}
Next in the actual Form this is my code. I am using a simple yes no message box to see if the timer can be stopped and recalled again when needed. You can apply your own locking mechanism.
I want the app to time out if it is InActive for 20 seconds. Change it as needed.
public partial class Form1 : Form
{
Timer timer;
const int TIMEOUT_DONE = 20000;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Reset();
}
void timer_Tick(object sender, EventArgs e)
{
//var ms = TIMEOUT_DONE - IdleCheck.GetLastInputTime();
if (IdleCheck.GetLastInputTime() > TIMEOUT_DONE)
{
DialogResult dialogResult = MessageBox.Show("Sure", "Some Title", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
Stop();
Reset();
}
}
}
public void Reset()
{
timer = new Timer();
timer.Interval = 10000;
timer.Tick += timer_Tick;
timer.Start();
}
public void Stop()
{
timer.Tick -= timer_Tick;
timer.Stop();
}
}
I'm searching for this for several hours now and was not able to find proper solution. I'm c# beginner.
I have a winforms app with a ListBox and a class that does some work and should run forever on separate thread. I want to push MyDataStruct to ListBox each time its created in WorkerClass.Work.
Later on, several WorkerClass instances should run simultaneously and I will have combobox to pick which instance data to feed to ListBox . Is it better to have WorkerClas return only single MyDataStruct and keep their queue in Form1 class or have a queue in each WorkerClass and exchange the entire queue with Form1 every time it changes?
is my void QueueToLb good way to add queue data to ListBox ?
thank you for your support.
public partial class Form1 : Form
{
Queue<MyDataStruct> qList;
MyDataStruct myDataStruct;
private void RunTask()
{
//how do I make MyLongTask to update either qList or myDataStuct
Task.Run(() =>
{
MyLongTask(0, 1000);
});
}
private void MyLongTask(int low, int high)
{
WorkerClass wc = new WorkerClass();
wc.Work(low,high);
}
private void QueueToLb()
{
//is this good way to update listbox from queue?
List<MyDataStruct> lstMds = qList.Reverse<MyDataStruct>().ToList<MyDataStruct>();
List<string> lstStr = new List<string>();
foreach (MyDataStruct m in lstMds)
{
lstStr.Add(m.ToString());
}
listBox1.DataSource = lstStr;
}
}
public class WorkerClass
{
Queue<MyDataStruct> qList; //not sure if its better to keep the queue here or in Form1
public WorkerClass()
{
qList = new Queue<MyDataStruct>();
}
public void Work(int low, int high) //does some work forever
{
while (true)
{
if (qList.Count > 11) qList.Dequeue();
MyDataStruct mds = new MyDataStruct();
Random random = new Random();
mds.dt = DateTime.Now;
mds.num = random.Next(low, high);
qList.Enqueue(mds);
Thread.Sleep(1000);
}
}
}
public class MyDataStruct
{
public DateTime dt;
public int num;
public override string ToString()
{
StringBuilder s = new StringBuilder();
s.Append(num.ToString());
s.Append(" - ");
s.Append(dt.ToShortDateString());
return s.ToString();
}
}
OK I think I figured how to use BackgroundWorker on this, I'll be happy if someone could verify it is correct
public partial class Form1 : Form
{
Queue<MyDataStruct> qList;
BackgroundWorker bw = new BackgroundWorker();
public Form1()
{
InitializeComponent();
bw.WorkerReportsProgress = true;
bw.DoWork += new DoWorkEventHandler(Bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
}
private void Form1_Load(object sender, EventArgs e)
{
qList = new Queue<MyDataStruct>(12);
}
private void button1_Click(object sender, EventArgs e)
{
bw.RunWorkerAsync();
}
private void MyLongTask(int low = 0, int high = 1000)
{
WorkerClass wc = new WorkerClass(bw);
wc.Work(low,high);
}
private void BindToLbWithQueue()
{
MyDataStruct mds = new MyDataStruct();
Random random = new Random();
mds.dt = DateTime.Now;
mds.num = random.Next(0, 1000);
qList.Enqueue(mds);
QueueToLb();
}
private void QueueToLb()
{
//is this good way to update listbox from queue?
List<MyDataStruct> lstMds = qList.Reverse<MyDataStruct>().ToList<MyDataStruct>();
List<string> lstStr = new List<string>();
foreach (MyDataStruct m in lstMds)
{
lstStr.Add(m.ToString());
}
listBox1.DataSource = lstStr;
}
#region worker
private void Bw_DoWork(object sender, DoWorkEventArgs e)
{
MyLongTask();
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
qList = (Queue<MyDataStruct>)e.UserState;
QueueToLb();
}
#endregion
}
public class WorkerClass
{
Queue<MyDataStruct> qList; //not sure if its better to keep the queue here or in Form1
BackgroundWorker bw = null;
public WorkerClass(BackgroundWorker bw)
{
this.bw = bw;
qList = new Queue<MyDataStruct>();
}
public void Work(int low, int high) //does some work forever
{
while (true)
{
if (qList.Count > 11) qList.Dequeue();
MyDataStruct mds = new MyDataStruct();
Random random = new Random();
mds.dt = DateTime.Now;
mds.num = random.Next(low, high);
qList.Enqueue(mds);
bw.ReportProgress(0, qList);
Thread.Sleep(1000);
}
}
}
public class MyDataStruct
{
public DateTime dt;
public int num;
public override string ToString()
{
StringBuilder s = new StringBuilder();
s.Append(num.ToString());
s.Append(" - ");
s.Append(dt.ToShortDateString());
return s.ToString();
}
}
Timer is working only one time. This service must be work in every 2minutes...
public partial class Service1 : ServiceBase
{
RuleContext entity = new RuleContext();
private int id;
private Timer _timer;
private DateTime _lastRun = DateTime.Now.AddDays(-1);
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
OnTimer();
}
public void OnTimer()
{
Timeout.Infinite);
_timer = new Timer();
_timer.Interval = 2 * 60 * 1000;
_timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
_timer.Enabled = true;
_timer.AutoReset = true;
_timer.Start();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// ignore the time, just compare the date
if (_lastRun.Date <= DateTime.Now.Date)
{
GetRule();
}
}
protected override void OnStop()
{
}
public void GetRule()
{
var query = from ruleset in entity.RuleSets
join rule in entity.Rules on ruleset.Id equals rule.RuleSetId
join schedulerule in entity.Schedules on rule.ScheduleId equals schedulerule.Id
select new
{
Id = ruleset.Id,
daily = schedulerule.Daily,
mountly = schedulerule.Monthly,
dayofMounth = schedulerule.DayOfMonth,
};
foreach (var q in query.ToList())
{
if (q.mountly && q.daily)
{
if (q.dayofMounth == (int)DateTime.Now.Day)
{
UpdateValue(q.Id);
}
}
else if (q.daily)
{
UpdateValue(q.Id);
}
else if (q.mountly)
{
if (q.dayofMounth == (int)DateTime.Now.Day)
{
UpdateValue(q.Id);
}
}
}
}
public void UpdateValue(int id)
{
var ruleSet = entity.RuleSets.First(k => k.Id == id);
ruleSet.RcvByte = 0;
ruleSet.SentByte = 0;
entity.SaveChanges();
}
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// ignore the time, just compare the date
if (_lastRun.Date <= DateTime.Now.Date)
{
GetRule();
}
}
Since the AutoReset property is set to true, no need to Stop and Start timer.
_timer.Stop();
this line is causing this problem. Remove it
I have a CountDownTimer class that updates a controller that updates the user interface. The problem i have is when i run my unit tests i get a NllReferenceException because the event handlder(Tick) is never initialized always null. What is the best possible solution to this problem? Or should i go about it differently. Thanks
public class CountDownTimer : ICountDownTimer
{
private int seconds; // Time in seconds
private int reSetValue; // Time in seconds
private System.Windows.Forms.Timer timer1;
public event TickHandler Tick;
public EventArgs e = null;
public delegate void TickHandler(CountDownTimer m, EventArgs e, int seconds);
public CountDownTimer(int seconds)
{
this.seconds = seconds;
reSetValue = seconds;
timer1 = new System.Windows.Forms.Timer();
timer1.Tick += new EventHandler(timer1_Tick); // Add Handler(timer1_Tick)
timer1.Interval = 1000; // 1 second
}
private void timer1_Tick(object sender, EventArgs e)
{
CallTickHandler();
if (getSeconds() == 0) // Stop Timer at 0
{
timer1.Stop(); // Stop timer
}
else
{
if (getSeconds() % 60 == 0 || getSeconds() >= 1 && getSeconds() <= 10)
{
CallTickHandler();
}
}
seconds--; // Decrement seconds
}
public void StartTimer()
{
timer1.Start();
}
public void StopTimer()
{
timer1.Stop();
}
public void ResetTimer()
{
timer1.Stop();
seconds = reSetValue;
CallTickHandler();
}
public void SetTimer(int seconds)
{
timer1.Stop();
this.seconds = getSeconds();
reSetValue = getSeconds();
CallTickHandler();
}
internal void CallTickHandler()
{
Tick(this, e, getSeconds());
}
public Boolean isEnabled()
{
return timer1.Enabled;
}
public int getSeconds()
{
return seconds;
}
}
public class Controller : ApplicationContext
{
//Store a reference to the UI
internal frmMain MainUI { get; set; }
private int seconds = 300;
CountDownTimer timer;
public Controller()
{
MainUI = new frmMain(this);
//We can do any necessary checks or changes to the MainUI here before it becomes visible
MainUI.Show();
timer = new CountDownTimer(seconds);
SubscribeToTickListener(timer);
TickUpdate(seconds);
}
internal void TickUpdate(string seconds)
{
MainUI.lblTimer.Text = ("" + Convert.ToInt32(seconds) / 60).PadLeft(2, '0') + "m:" + ("" + Convert.ToInt32(seconds) % 60).PadLeft(2, '0') + "s";
}
internal void TickUpdate(int seconds)
{
MainUI.lblTimer.Text = ("" + seconds / 60).PadLeft(2, '0') + "m:" + ("" + seconds % 60).PadLeft(2, '0') + "s";
if (seconds <= 10)
{
//ss.Speak(seconds.ToString());
}
else
{
//ss.Speak((seconds / 60).ToString() + " minute warning");
}
}
internal void StartTimer()
{
timer.StartTimer();
}
internal void ResetTimer()
{
timer.ResetTimer();
}
internal void StopTimer()
{
timer.StopTimer();
}
internal void SetTimer(int seconds)
{
timer.SetTimer(seconds);
}
public void SubscribeToTickListener(CountDownTimer cdt)
{
cdt.Tick += new CountDownTimer.TickHandler(TickMsgRecieved);
}
public void TickMsgRecieved(CountDownTimer cdt, EventArgs e, int seconds)
{
TickUpdate(seconds);
TickUpdate(seconds.ToString());
}
}
public class CountDownTimerTests
{
private CountDownTimer t = new CountDownTimer(300);
[TestMethod()]
public void CountDownTimerTest()
{
CountDownTimer t = new CountDownTimer(300);
}
[TestMethod()]
public void StartTimerTest()
{
//CountDownTimer t = new CountDownTimer(300);
t.StartTimer();
Boolean expected = t.isEnabled();
Boolean actual = true;
Assert.AreEqual(expected, actual);
}
[TestMethod()]
public void StopTimerTest()
{
//CountDownTimer t = new CountDownTimer(300);
t.StartTimer();
t.StopTimer();
Boolean expected = t.isEnabled();
Boolean actual = false;
Assert.AreEqual(expected, actual);
}
[TestMethod()]
public void ResetTimerTest()
{
int expected = t.getSeconds();
t.ResetTimer();
int actual = t.getSeconds();
Assert.AreEqual(expected, actual);
}
[TestMethod()]
public void SetTimerTest()
{
int expected = t.getSeconds();
t.SetTimer(120);
int actual = t.getSeconds();
Assert.AreEqual(expected, actual);
}
}
In this case you can probably use a mock implementation of the event. I would add the following mock event to your test class to simulate a consumer of the CountDownTimer class.
[TestInitialize]
public void TestSetup()
{
t.Tick += new CountDownTimer.TickHandler(MockTickEvent);
}
[TestCleanup]
public void TestCleanup()
{
t.Tick -= MockTickEvent;
}
void MockTickEvent(CountDownTimer m, EventArgs e, int seconds)
{
///you may need to add further test code here to fully cover your code
return;
}