I am trying to create an event that executes a function when a certain amount of time has changed. The timer is done by another code, it's supposed to call Plus(1), but will that change all timers (if I create multiple)? And this code is not actually working.
namespace #event
{
class Program
{
static void Main(string[] args)
{
Tick tijd = new Tick();
tijd.interval = 10;
tijd.TijdVeranderd += new EventHandler(Uitvoeren);
dynamic func = new Tick();
for (int i = 0; i < 100; i++)
{
func.Plus(1);
}
Console.ReadLine();
}
static void Uitvoeren(object sender, EventArgs e)
{
Console.WriteLine("Uitgevoerd!");
}
}
public class Tick
{
public event EventHandler TijdVeranderd;
public int interval;
private int tijd;
public void Plus(int i)
{
tijd += 1;
}
public int Verander
{
get { return this.tijd; }
set
{
this.tijd = value;
if (tijd == interval)
{
if (this.TijdVeranderd != null)
this.TijdVeranderd(this, new EventArgs());
tijd = 0;
}
}
}
public Tick() { }
}
}
EDIT: I don't want to use the .net timer, I want to create my own.
Just use .net timer like this:
System.Timers.Timer aTimer = new System.Timers.Timer();
aTimer.Elapsed += new System.Timers.ElapsedEventHandler(aTimer_Elapsed);
aTimer.Interval = 1000; //here you can set your interval
aTimer.Start();
Here you can catch the event and call other method:
void aTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//TODO: call your method like "Plus"
}
There seem to be a couple of errors in your code:
First of all, in Main, you are calling Plus() on a different instance of Tick than the one that you configured. Try using tijd.Plus(1) instead of func.Plus(1).
Also, in the implementation of Plus, when you increment the private variable tijd, the code associated with the property Verander does not get executed, so no events ever fire. To quickly fix, increment Verander instead of tijd.
namespace #event
{
class Program
{
static void Main(string[] args)
{
Tick tijd = new Tick();
tijd.interval = 10;
tijd.TijdVeranderd += new EventHandler(Uitvoeren);
for (int i = 0; i < 100; i++)
{
tijd.Plus(1);
}
Console.ReadLine();
}
static void Uitvoeren(object sender, EventArgs e)
{
Console.WriteLine("Uitgevoerd!");
}
}
public class Tick
{
public event EventHandler TijdVeranderd;
public int interval;
private int tijd;
public void Plus(int i)
{
Verander += 1;
}
public int Verander
{
get { return this.tijd; }
set
{
this.tijd = value;
if (tijd == interval)
{
if (this.TijdVeranderd != null)
this.TijdVeranderd(this, new EventArgs());
tijd = 0;
}
}
}
public Tick() { }
}
}
You can try with this code
private static System.Timers.Timer aTimer;
public static void Main()
{
// Create a timer with a ten second interval.
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;
Console.WriteLine("Press the Enter key to exit the program.");
Console.ReadLine();
// If the timer is declared in a long-running method, use
// KeepAlive to prevent garbage collection from occurring
// before the method ends.
//GC.KeepAlive(aTimer);
}
// Specify what you want to happen when the Elapsed event is
// raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}
I don't know why you wouldn't use a system timer, but here's an [untested] implementation of a timer that should do the trick:
class MyCrudeTimer : IDisposable
{
public event EventHandler Alarm ;
public TimeSpan Duration { get ; private set ; }
public bool AutomaticallyReset { get ; private set ; }
public bool IsRunning { get ; private set ; }
private Thread timerThread ;
private ManualResetEvent start ;
private void TimerCore()
{
try
{
while ( start.WaitOne() )
{
System.Threading.Thread.Sleep( Duration ) ;
Alarm( this , new EventArgs() ) ;
}
}
catch ( ThreadAbortException )
{
}
catch ( ThreadInterruptedException )
{
}
return ;
}
public MyCrudeTimer( TimeSpan duration , bool autoReset )
{
if ( duration <= TimeSpan.Zero ) throw new ArgumentOutOfRangeException("duration must be positive","duration") ;
this.Duration = duration ;
this.AutomaticallyReset = autoReset ;
this.start = new ManualResetEvent(false) ;
this.timerThread = new Thread( TimerCore ) ;
this.timerThread.Start() ;
return ;
}
public void Start()
{
if ( IsRunning ) throw new InvalidOperationException() ;
IsRunning = true ;
start.Set() ;
return ;
}
public void Stop()
{
if ( !IsRunning ) throw new InvalidOperationException() ;
IsRunning = false ;
start.Reset() ;
return ;
}
public void Dispose()
{
try
{
if ( this.timerThread != null )
{
this.timerThread.Abort() ;
this.timerThread = null ;
}
}
catch
{
}
return ;
}
}
Related
Please go through the following code which is an oversimplification of the code I have.
I need to know how once the timer is elapsed, how to return control to the main user control class, preferably to the same case within the switch statement.
public partial class ucClass : UserControl
{
int A;
Label labelTimer = new Label();
sec secObj = new sec();
public execute()
{
switch(A)
{
case 1:
secObj.initiate(labelTimer, 10);
break:
case 2:
......
}
}
}
class sec
{
public System.Windows.Forms.Timer timer;
private Label labelTimer = new Label();
private int expectedCount = 0;
private int actualCount = 0;
public void initiate(Label labelTimer, int count)
{
this.expectedCount = count;
this.labelTimer = labelTimer;
this.timer.Interval = 1000;
startTimer();
}
private void startTimer()
{
this.timer.Start();
this.timer.Tick += this.timerElapsed;
}
private void timerElapsed(object sender, EventArgs e)
{
this.timer.Dispose();
if(expectedCount > actualCount)
{
this.actualCount += 1;
this.labelTimer.Text = this.actualCount.ToString();
this.startTimer();
}
else
{
//this is where I need to notify the main class that timer has expired and go to case 2
}
}
}
You can achieve the behavior that you want with events:
public partial class ucClass : UserControl
{
int A;
Label labelTimer = new Label();
sec secObj = new sec();
public ucClass()
{
// Listen to event from timer
secObj.TimerExpired += (sender, args) =>
{
A = args.Count;
execute();
};
}
public void execute()
{
switch(A)
{
case 1:
secObj.initiate(labelTimer, 10);
break:
case 2:
......
}
}
}
class sec
{
public System.Windows.Forms.Timer timer;
public event EventHandler<TimerExpiredEventArgs> TimerExpired;
private Label labelTimer = new Label();
private int expectedCount = 0;
private int actualCount = 0;
public void initiate(Label labelTimer, int count)
{
this.expectedCount = count;
this.labelTimer = labelTimer;
this.timer.Interval = 1000;
startTimer();
}
private void startTimer()
{
this.timer.Start();
this.timer.Tick += this.timerElapsed;
}
private void timerElapsed(object sender, EventArgs e)
{
this.timer.Dispose();
if(expectedCount > actualCount)
{
this.actualCount += 1;
this.labelTimer.Text = this.actualCount.ToString();
this.startTimer();
}
else
{
// Send event with count
TimerExpired?.Invoke(this, new TimerExpiredEventArgs
{
Count = actualCount
});
}
}
}
public class TimerExpiredEventArgs
{
public int Count { get; set; }
}
I would recommend looking into the following;
The MVVM pattern
This will allow you to seperate the UI logic (passing around labels etc) and the control logic (timers etc).
Reactive Extensions (https://github.com/dotnet/reactive)
This would allow for a very simple timer:
Observable
.Interval(TimeSpan.FromSeconds(1))
.Subscribe(count => {
labelTimer.Text = count.ToString();
if (count > actualCount) {
A = args.Count;
execute();
}
});
I have a class with timer like below
public class helper
{
Timer timer = new Timer();
private int counter = 0;
private int returnCode = 0;
public int Process()
{
SetTimer();
Console.WriteLine("The application started ");
return counter;
}
public void SetTimer()
{
int optionalWay = 0;
// Create a timer with a two second interval.
timer = new System.Timers.Timer(2000);
// Hook up the Elapsed event for the timer.
timer.Elapsed += (sender, e) => OnTimedEvent(sender, e, optionalWay);
timer.AutoReset = true;
timer.Enabled = true;
}
private void OnTimedEvent(Object source, ElapsedEventArgs e, int optionalWay)
{
counter++;
Console.WriteLine("Timer is ticking");
if (counter == 10)
{
timer.Stop();
timer.Dispose();
returnCode = returnCode + 1;
}
}
}
I have main function like this below
public static void Main()
{
helper helper = new helper();
int code = helper.Process();
Console.WriteLine("Main " + code.ToString());
Console.ReadLine();
}
what I want to do is return to main when my timer is stopped, not before that
, my timer class is running fine, main is getting printed like below
So main should wait till the result from timer is 1. And then end process
The code is working as it should. There is nothing inside the helper.Process() function that can wait or block the execution, so the function is returning immediately to the main before the OnTimedEvent is even executed.
A workaround can be done by implementing an event in the helper class and raise that event after the timer completes its work. And the main can listen to that event and act accordingly.
public class helper
{
Timer timer = new Timer();
private int counter = 0;
private int returnCode = 0;
public event EventHandler<int> Done;
...
private void OnTimedEvent(Object source, ElapsedEventArgs e, int optionalWay)
{
counter++;
Console.WriteLine("Timer is ticking");
if (counter == 10)
{
timer.Stop();
timer.Dispose();
returnCode = returnCode + 1;
if (Done != null)
{
Done.Invoke(this, returnCode);
}
}
}
}
And in the Program.cs
static void Main(string[] args)
{
helper helper = new helper();
helper.Done += helper_Done;
helper.Process();
Console.ReadLine();
}
static void helper_Done(object sender, int e)
{
Console.WriteLine("Main " + e.ToString());
}
Update
The Timer class uses a new thread from ThreadPool to execute the Elapsed event handler. So it cannot return to the Main which is running on a different thread. In short: what you are trying to do cannot not be achieved with a Timer.
Here is another solution using Thread.Sleep() which will satisfy your requirement, but keep in mind using Thread.Sleep() like this is not recommended.
public class helper
{
private int counter = 0;
private int returnCode = 0;
public int Process()
{
Console.WriteLine("The application started ");
StartTimer(2000);
return returnCode;
}
private void StartTimer(int ms)
{
while (counter++ < 10)
{
System.Threading.Thread.Sleep(ms);
Console.WriteLine("Timer is ticking");
}
returnCode = returnCode + 1;
}
}
class Program
{
static void Main(string[] args)
{
helper helper = new helper();
int code = helper.Process();
Console.WriteLine("Main " + code.ToString());
Console.ReadLine();
}
}
Again, this is NOT a good practice to use Thread.Sleep for a delayed execution and Thread.Sleep is less accurate compare to Timer.Elapsed. Try to change the design of your application and use Event or Callback function.
Change the Process function of helper class to accept a callback:
public void Process(Action<int> callBack)
{
SetTimer();
Console.WriteLine("The application started ");
if (timer != null)
timer.Disposed += (o, e) => callBack(counter);
}
Change the main function to send the callback:
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
helper helper = new helper();
helper.Process(c => Console.WriteLine("Main " + c.ToString()));
Console.ReadLine();
}
I have two options in mind, one of them and the ugliest, is to loop until timer is stopped, basically doing so:
public class helper
{
Timer timer = new Timer();
private int counter = 0;
private int returnCode = 0;
private bool timerWorking = false;
public int Process()
{
SetTimer();
Console.WriteLine("The application started ");
while(timerWorking){}
return counter;
}
public void SetTimer()
{
// All the staff you already have
timerWorking = true;
}
private void OnTimedEvent(Object source, ElapsedEventArgs e, int optionalWay)
{
counter++;
Console.WriteLine("Timer is ticking");
if (counter == 10)
{
//All the staff you already have
timerWorking = false;
}
}
}
Or, the more elegant, passing or registering a callback to be executed once the ending point is reached:
public class helper
{
Timer timer = new Timer();
private int counter = 0;
private int returnCode = 0;
Action<int> _doAfterTimerEnds
public void Process(Action<int> doAfterTimerEnds)
{
SetTimer();
_doAfterTimerEnds = doAfterTimerEnds;
Console.WriteLine("The application started ");
}
public void SetTimer()
{
int optionalWay = 0;
// Create a timer with a two second interval.
timer = new System.Timers.Timer(2000);
// Hook up the Elapsed event for the timer.
timer.Elapsed += (sender, e) => OnTimedEvent(sender, e, optionalWay);
timer.AutoReset = true;
timer.Enabled = true;
}
private void OnTimedEvent(Object source, ElapsedEventArgs e, int optionalWay)
{
counter++;
Console.WriteLine("Timer is ticking");
if (counter == 10)
{
timer.Stop();
timer.Dispose();
returnCode = returnCode + 1;
_doAfterTimerEnds(returnCode)
}
}
}
public static void Main()
{
var returnCode = 0;
var helper = new helper();
helper.Process(code => returnCode = code);
while (returnCode != 1) {}
Console.WriteLine("Main " + returnCode);
Console.ReadLine();
}
UPDATE: I've tested this last version and it is working as expected.
I'm creating an Windowns phone 8 app(c#), its a countdown interval timer, so there is prepare time(10 sec), work time(20 sec), rest time(10 sec). I have these variables
`TimeSpan prepInterval = new TimeSpan(0, 0, 0, 10);
TimeSpan workInterval = new TimeSpan(0, 0, 0, 20);
TimeSpan restInterval = new TimeSpan(0, 0, 0, 10);`
I can't wrap my head around having them implementing them one after another when they hit 0. So when prepare time is done, the work timer is to start and when thats finised, the rest timer is to start.
If you would like to have some more broken down logic in all of this, maybe you can create some classes based on a simple interface, like the following:
interface ITimerAction
{
int Seconds { get; set; }
bool Started { get; }
bool Completed { get; }
void OnStart();
void OnComplete();
}
interface ITimerActionList
{
void Add(ITimerAction action);
void Work();
event EventHandler OnCompletedEvent;
}
This would then allow you to create an abstract TimerAction class, and TimerActionList
abstract class TimerAction : ITimerAction
{
public virtual int Seconds
{
get;
set;
}
public virtual bool Completed
{
get;
protected set;
}
public virtual bool Started
{
get;
protected set;
}
public abstract void OnStart();
public abstract void OnComplete();
}
class TimerActionList : ITimerActionList
{
public event EventHandler OnCompletedEvent;
private readonly IList<ITimerAction> actions = new List<ITimerAction>();
private bool working = false;
private Thread myThread;
public void Add(ITimerAction action)
{
if (working)
{
throw new InvalidOperationException("Cannot add new timers when work is already in progress");
}
actions.Add(action);
}
protected virtual void DoWork()
{
working = true;
int currentStep = 0, maxSteps = actions.Count;
while (currentStep < maxSteps)
{
ITimerAction action = actions[currentStep];
if (!action.Started)
{
action.OnStart();
}
if (action.Completed)
{
currentStep++;
continue;
}
if (action.Seconds == 0)
{
action.OnComplete();
continue;
}
action.Seconds--;
Thread.Sleep(1000);
}
Completed();
}
public void Work()
{
if (working)
{
throw new InvalidOperationException("Already running!");
}
working = true;
myThread = new Thread(DoWork);
myThread.Start();
}
protected virtual void Completed()
{
myThread = null;
working = false;
actions.Clear();
var local = OnCompletedEvent;
if (local != null)
{
local.Invoke(this, EventArgs.Empty);
}
}
}
You could then write the classes that inherit from the TimerAction class, that could handle an action before and after the timer ran through :)
class PrepareTimer : TimerAction
{
public override void OnStart()
{
Console.WriteLine("Preparing");
Started = true;
}
public override void OnComplete()
{
Console.WriteLine("Prepare ready");
Completed = true;
}
}
class WorkTimer : TimerAction
{
public override void OnStart()
{
Console.WriteLine("Working");
Started = true;
}
public override void OnComplete()
{
Console.WriteLine("Work ready");
Completed = true;
}
}
class CoolDownTimer : TimerAction
{
public override void OnStart()
{
Console.WriteLine("Cooling down");
Started = true;
}
public override void OnComplete()
{
Console.WriteLine("Cooldown ready");
Completed = true;
}
}
And then you could test the code as such
static void Main(string[] args)
{
bool done = false;
ITimerActionList mylist = new TimerActionList();
mylist.Add(new PrepareTimer { Seconds = 1 });
mylist.Add(new WorkTimer { Seconds = 2 });
mylist.Add(new CoolDownTimer { Seconds = 1 });
mylist.OnCompletedEvent += (sender, e) =>
{
done = true;
};
mylist.Work();
while (!done)
{
// timer is running
}
Console.WriteLine("Done!");
}
(Console program, but i guess that also goes to demonstrate?)
Here's an example based on deathismyfriend's and Hans Passant's suggestions:
var start = new DateTime();
var stage = 0;
var timer = new System.Timers.Timer(100);
timer.Elapsed += (s, e) =>
{
var elapsed = DateTime.Now - start;
int duration = stage == 1 ? 20 : 10;
if (elapsed.TotalSeconds > duration)
{
start = DateTime.Now;
stage++;
if (stage > 2)
timer.Stop();
}
};
start = DateTime.Now;
stage = 0;
timer.Start();
I have custom thread which parses WiFi networks and updates the UI (DataGridView and graphs). Here is the thread method:
private void RefreshThread()
{
var watch = Stopwatch.StartNew();
while (true)
{
UpdateAllNetworks();
UpdateAllInterferences();
UpdateAllColors();
switch (ActivePage)
{
case Page.Start:
break;
case Page.Networks:
this.Invoke((MethodInvoker)delegate
{
UpdateDataGridWithNetworks();
ClearGraphs();
Draw24GHzGraph();
DrawSignalsOverTimeGraph();
});
break;
case Page.Channels:
break;
case Page.Analyze:
break;
default:
break;
}
watch.Stop();
int elapsedMs = (int) watch.ElapsedMilliseconds;
if (elapsedMs < Constants.NetworksRefreshThreadInterval)
Thread.Sleep(Constants.NetworksRefreshThreadInterval - elapsedMs);
}
}
Custom DataGridView:
public class CustomDataGridView : DataGridView
{
...
protected override void OnCellClick(DataGridViewCellEventArgs e)
{
base.OnCellClick(e);
int Index = e.RowIndex;
if (Index != -1)
{
DataGridViewRow row = Rows[Index];
PrimaryKeyForSelectedRow = row.Cells[KeyName].Value.ToString();
}
}
}
The DataGridView is my custom DataGrid where I have a click event handler. I have observed that sometimes the event handler isn't called but in most cases it is.
What could be the problem? Is it related to multithreading or the event isn't queued?
Your code blocks main thread, use separate thread for your network details update. Here is quick sample how it done.
class Program
{
static void Main(string[] args)
{
var helper = new Looper(5000, YourMethod_RefreshThread);
helper.Start();
}
private static void YourMethod_RefreshThread()
{
Console.WriteLine(DateTime.Now);
}
}
public class Looper
{
private readonly Action _callback;
private readonly int _interval;
public Looper(int interval, Action callback)
{
if(interval <=0)
{
throw new ArgumentOutOfRangeException("interval");
}
if(callback == null)
{
throw new ArgumentNullException("callback");
}
_interval = interval;
_callback = callback;
}
private void Work()
{
var next = Environment.TickCount;
do
{
if (Environment.TickCount >= next)
{
_callback();
next = Environment.TickCount + _interval;
}
Thread.Sleep(_interval);
} while (IsRunning);
}
public void Start()
{
if (IsRunning)
{
return;
}
var thread = new Thread(Work);
thread.Start();
IsRunning = true;
}
public void Stop()
{
this.IsRunning = false;
}
public bool IsRunning { get; private set; }
I am trying to wrap my head around threading in C# but I am having difficulty implementing this behavior.
I need a simple yes/no dialog that returns DialogResult.No when 30 seconds are passed.
What I've got so far is this:
Thread th = new Thread(() =>
{
try
{
result = message.ShowDialog();
}
catch (Exception)
{
}
});
th.Start();
Thread.Sleep(30000);
th.Abort();
When I select Yes or No on the dialog it still waits out the 30 seconds, I need the thread to stop when response is received.
This is probably a no brainer but I'm relatively new to C# and could really use some help on this.
You could use a Timer when you initialize your Form.
When the timer expired, you close your Form.
Timer time1 = new Timer();
time1.Elapsed += new ElapsedEventHandler(OnTimedEvent);
time1.Interval = 30000; // 30 secs
...
time1.Enabled = true; // Start the timer
message.ShowDialog();
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
// Close your Form
message.Close();
// Maybe you could set a variable, that indicates you, that the timer timed out
}
You have to overwrite ShowDialog() and ShowDialog(owner). When your show dialog will be called you start a timer and forward to the base.ShowDialog(). When the timer raises the tick event simply call Close().
Here an example implementation:
public partial class FormTimed : Form
{
private String _OriginalText;
private DateTime _StartTime;
private Timer _Timer;
public FormTimed()
{
InitializeComponent();
InitializeTimer();
Duration = TimeSpan.FromSeconds(10);
}
[DefaultValue(typeof(TimeSpan), "00:00:10")]
public TimeSpan Duration { get; set; }
public override string Text
{
get
{
return _OriginalText;
}
set
{
_OriginalText = value;
base.Text = value;
}
}
public void DisableTimer()
{
_Timer.Stop();
base.Text = _OriginalText;
}
public void ResetTimer()
{
_StartTime = DateTime.UtcNow;
_Timer.Start();
}
public new DialogResult ShowDialog()
{
StartTimer();
return base.ShowDialog();
}
public new DialogResult ShowDialog(IWin32Window owner)
{
StartTimer();
return base.ShowDialog(owner);
}
private void InitializeTimer()
{
_Timer = new Timer();
_Timer.Interval = 100;
_Timer.Tick += OnTimerTick;
}
private void OnTimerTick(object sender, EventArgs e)
{
var finishTime = _StartTime + Duration;
var remainingDuration = finishTime - DateTime.UtcNow;
if (remainingDuration < TimeSpan.Zero)
{
Close();
}
base.Text = _OriginalText + " (" + (int)remainingDuration.TotalSeconds + ")";
}
private void StartTimer()
{
_StartTime = DateTime.UtcNow;
_Timer.Start();
}
}