Tracking when x number of events have fired - c#

Usually this is the stuff i would spend a few hours browsing google and stackoverflow for, however i ran into the problem of how the heck do i word this for a search engine.
I hoping there is a simple way of achieving this, as my current method feels far to "hackish"
What I need to do, if track when several sources of data have completed their loading, and only when all have completed do i load a new view (this is WPF mvvm). Now the data is loaded via a static class termed Repository each one creates a thread and ensure they only a single load operation can happen at once (to avoid multiple threads trying to load into the same collection), each of these classes fires an event called LoadingCompleted when they have finished loading.
I have a single location that loads a large portion of the data (for the first time, there are other locations where the data is reloaded however) what i planned was to hook into each repositories OnLoaded event, and keep track of which have already returned, and when one is returned, mark it as loaded and check to see if any remain. If none remain load the new view, else do nothing.
Something like this:
ShipmentRepository.LoadingComplete += ShipmentRepository_LoadingComplete;
ContainerRepository.LoadingComplete += ContainerRepository_LoadingComplete;
void ContainerRepository_LoadingComplete(object sender, EventArgs e)
{
_containerLoaded = true;
CheckLoaded();
}
void ShipmentRepository_LoadingComplete(object sender, EventArgs e)
{
_shipmentsLoaded = true;
CheckLoaded();
}
private void CheckLoaded()
{
if(_shipmentsLoaded && _containersLoaded && _packagesLoaded)
{
LoadView();
}
}
However as i mentioned this feels clumbsy and hackish, I was hoping there was a cleaner method of doing this.

You can achieve this with Reactive Extensions and using Observable.FromEventPattern in conjunction with the Observable.Zip method. You should be able to do something like:
var shipmentRepositoryLoadingComplete = Observable.FromEventPattern<EventHandler,EventArgs>(h => ShipmentRepository.LoadingComplete += h, h => ShipmentRepository.LoadingComplete -= h);
var containerRepositoryLoadingComplete = Observable.FromEventPattern<EventHandler, EventArgs>(h => ContainerRepository.LoadingComplete += h, h => ContainerRepository.LoadingComplete -= h);
Then you subscibe to the observalbes like this:
var subscription = Observable.Zip(shipmentRepositoryLoadingComplete, containerRepositoryLoadingComplete)
.Subscribe(l => LoadView()));
The subscirption needs to stay alive, so you can save this as a private variable. When both complete events are invoked, the LoadView method should be called. Here is a working console example I used to test this method.
using System;
using System.Reactive.Linq;
namespace RxEventCombine
{
class Program
{
public event EventHandler event1;
public event EventHandler event2;
public event EventHandler event3;
public Program()
{
event1 += Event1Completed;
event2 += Event2Completed;
event3 += Event3Completed;
}
public void Event1Completed(object sender, EventArgs args)
{
Console.WriteLine("Event 1 completed");
}
public void Event2Completed(object sender, EventArgs args)
{
Console.WriteLine("Event 2 completed");
}
public void Event3Completed(object sender, EventArgs args)
{
Console.WriteLine("Event 3 completed");
}
static void Main(string[] args)
{
var program = new Program();
var event1Observable = Observable.FromEventPattern<EventHandler,EventArgs>(h => program.event1 += h, h => program.event1 -= h);
var event2Observable = Observable.FromEventPattern<EventHandler, EventArgs>(h => program.event2 += h, h => program.event2 -= h);
var event3Observable = Observable.FromEventPattern<EventHandler, EventArgs>(h => program.event3 += h, h => program.event3 -= h);
using (var subscription = Observable.Zip(event1Observable, event2Observable, event3Observable)
.Subscribe(l => Console.WriteLine("All events completed")))
{
Console.WriteLine("Invoke event 1");
program.event1.Invoke(null, null);
Console.WriteLine("Invoke event 2");
program.event2.Invoke(null, null);
Console.WriteLine("Invoke event 3");
program.event3.Invoke(null, null);
}
Console.ReadKey();
}
}
}
Output
Invoke event 1
Event 1 completed
Invoke event 2
Event 2 completed
Invoke event 3
Event 3 completed
All events completed

Another way to do this: Add a property LoadingCompleted. For every instance you start a thread return that object to a list. On every loadcompleted set the property to true and in the place you catch the load completed loop through the list (myList.Any(x=>LoadingCompleted == false)) to figure out if everything is completed.
Not the most correct way to do it. But reading your scenario this might do the job.

If you are loading the shipments, containers and packages as asynchronous task then you have several options. As others suggested you can use WhenAll or Join() to wait for all threads to finish before proceeding. However, if your threads have to stay alive and the threads don't stop when they have finished loading, you can use the System.Threading.CountdownEvent as following:
Edit
Added how I would set up the threads and handle the events. Also moved the example from the static Program to an instance, more closely resembeling your situation. Again, if you do not need to do anything in the threads after they have loaded the data, just skip the CountdownEvent altogether and wait for all threads to finish. Much simpler, does not need events and can be achieved using Join() or in this case Task.WaitAll().
class Program
{
static void Main(string[] args)
{
var myWpfObject = new MyWpfObject();
}
}
public class MyWpfObject
{
CountdownEvent countdownEvent;
public MyWpfObject()
{
ShipmentRepository ShipmentRepository = new ShipmentRepository();
ContainerRepository ContainerRepository = new ContainerRepository();
PackageRepository PackageRepository = new PackageRepository();
ShipmentRepository.LoadingComplete += Repository_LoadingComplete;
ContainerRepository.LoadingComplete += Repository_LoadingComplete;
PackageRepository.LoadingComplete += Repository_LoadingComplete;
Task[] loadingTasks = new Task[] {
new Task(ShipmentRepository.Load),
new Task(ContainerRepository.Load),
new Task(PackageRepository.Load)
};
countdownEvent = new CountdownEvent(loadingTasks.Length);
foreach (var task in loadingTasks)
task.Start();
// Wait till everything is loaded.
countdownEvent.Wait();
Console.WriteLine("Everything Loaded");
//Wait till aditional tasks are completed.
Task.WaitAll(loadingTasks);
Console.WriteLine("Everything Completed");
Console.ReadKey();
}
public void Repository_LoadingComplete(object sender, EventArgs e)
{
countdownEvent.Signal();
}
}
And a mock Repository class:
public class ShipmentRepository
{
public ShipmentRepository()
{
}
public void Load()
{
//Simulate work
Thread.Sleep(1000);
if (LoadingComplete != null)
LoadingComplete(this, new EventArgs());
Console.WriteLine("Finished loading shipments");
DoAditionalWork();
}
private void DoAditionalWork()
{
//Do aditional work after everything is loaded
Thread.Sleep(5000);
Console.WriteLine("Finished aditional shipment work");
}
public event EventHandler LoadingComplete;
}

Related

How to reduce frequency of continuously fired event's event handling

I am learning about tasks and async/await in c#. So please consider the stupidity of my question.
There is an event DummyEvent in a class. An event handler DummyEventHandler is subscribed to this event and it handles a large amount of CPU bound task, which is actually not needed to be used so frequently.
For that reason, if DummyEvent is fired continuously, I want DummyEventHandler to respond either at a reduced frequency, or respond at the end of that continuity.
So, my idea is to extract the large task into a separate Task and made it to delay 500 millisecond before it proceeds. After the delay ends, it will check whether the same Task has been scheduled again (continuous event fire) or not and avoid the large calculation if true.
Here is my naive implementation of that idea:
int ReducedCall = 0;
int TotalCallActual = 0;
protected void DummyEventHandler(object sender, bool arg)
{
TotalCallActual++;
LargeCPUBoundTask(); // there is a green underline here, but I think it's ok, or.. is it?
}
async Task LargeCPUBoundTask()
{
ReducedCall = TotalCallActual;
await Task.Delay(500);
// if this task is called again in this time, TotalCallActual will increase
if (ReducedCall == TotalCallActual)
{
// do all the large tasks
……
ReducedCall = 0;
TotalCallActual = 0;
}
}
But the problem is, I am not getting what I want. The line Task.Delay(500) doesn't actually await , or, if it does wait, there is something wrong because I experience staggering .
Any better idea, or any improvement / correction?
Ask for any additional information.
Thanks
You can leverage Reactive Extensions to do this:
void Main()
{
var generator = new EventGenerator();
var observable = Observable.FromEventPattern<EventHandler<bool>, bool>(
h => generator.MyEvent += h,
h => generator.MyEvent -= h);
observable
.Throttle(TimeSpan.FromSeconds(1))
.Subscribe(s =>
{
Console.WriteLine("doing something");
});
// simulate rapid firing event
for(int i = 0; i <= 100; i++)
generator.RaiseEvent();
// when no longer interested, dispose the subscription
subscription.Dispose();
}
public class EventGenerator
{
public event EventHandler<bool> MyEvent;
public void RaiseEvent()
{
if (MyEvent != null)
{
MyEvent(this, false);
}
}
}
The Throttle operator as coded above will allow a value (event) getting true every second.
So in the above code example the text doing something will only be printed once (after a second) even while the event is fired many times.
Edit
By the way, the reason for the green line is that your Task is not awaited. To fix it alter the code to:
protected async void DummyEventHandler(object sender, bool arg)
{
TotalCallActual++;
await LargeCPUBoundTask(); // there is no more green underline here
}
Unfortunately this will still not solve your issue as an event cannot be awaited so if the event is raised again while LargeCPUBoundTask is still running another call to LargeCPUBoundTask will be made so the work is overlapping if you get what I mean. In other words, that is why your code does not work.
I would use the timer event handler instead of your DummyEventHandler
Just adjust the frequency in milisencond of the timer and that will be it. You can create a timer via code without adding it to a form as a control. I think it is in the common controls lib.
Hope this helps. Good luck.
I spent some more time thinking about this problem and the assumption I made with my first solution was that the event is continuously firing, when it could just be firing part of the time for a while and then stop in the real problem.
In cases like this, the CPU bound task would only occur on the first event firing and then if the events finish firing before that CPU bound task completes, the remaining events would not get handled. But you wouldn't want to handle all of them, just the "last" one (not necessarily the actual last one, just one more to take care of the "cleanup").
So I've updated my answer to include the use case where there are frequent yet intermittent (i.e. burst of events then quiet) the correct thing would occur and a final run of the CPU bound task would happen (but still no more than 1 CPU bound task running at a time).
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Sender s = new Sender();
using (Listener l = new Listener(s))
{
s.BeginDemonstration();
}
}
}
class Sender
{
const int ATTEMPTED_CALLS = 1000000;
internal EventHandler frequencyReducedHandler;
internal int actualCalls = 0;
internal int ignoredCalls = 0;
Task[] tasks = new Task[ATTEMPTED_CALLS];
internal void BeginDemonstration()
{
int attemptedCalls;
for (attemptedCalls = 0; attemptedCalls < ATTEMPTED_CALLS; attemptedCalls++)
{
tasks[attemptedCalls] = Task.Run(() => frequencyReducedHandler.Invoke(this, EventArgs.Empty));
//frequencyReducedHandler?.BeginInvoke(this, EventArgs.Empty, null, null);
}
if (tasks[0] != null)
{
Task.WaitAll(tasks, Timeout.Infinite);
}
Console.WriteLine($"Attempted: {attemptedCalls}\tActual: {actualCalls}\tIgnored: {ignoredCalls}");
Console.ReadKey();
}
}
class Listener : IDisposable
{
enum State
{
Waiting,
Running,
Queued
}
private readonly AutoResetEvent m_SingleEntry = new AutoResetEvent(true);
private readonly Sender m_Sender;
private int m_CurrentState = (int)State.Waiting;
internal Listener(Sender sender)
{
m_Sender = sender;
m_Sender.frequencyReducedHandler += Handler;
}
private async void Handler(object sender, EventArgs args)
{
int state = Interlocked.Increment(ref m_CurrentState);
try
{
if (state <= (int)State.Queued) // Previous state was WAITING or RUNNING
{
// Ensure only one run at a time
m_SingleEntry.WaitOne();
try
{
// Only one thread at a time here so
// no need for Interlocked.Increment
m_Sender.actualCalls++;
// Execute CPU intensive task
await Task.Delay(500);
}
finally
{
// Allow a waiting thread to proceed
m_SingleEntry.Set();
}
}
else
{
Interlocked.Increment(ref m_Sender.ignoredCalls);
}
}
finally
{
Interlocked.Decrement(ref m_CurrentState);
}
}
public void Dispose()
{
m_SingleEntry?.Dispose();
}
}

Constant running process on a sperate thread blocking a UI thread

i am trying to use a third party telnet library "active expert" for a basic telnet session.
in my UI code behind i have something like
private async void Button_Click(object sender, RoutedEventArgs e)
{
var ts = new TelnetService();
await ts.DoConnect(node);
}
and my TelnetService looks like this
public class TelnetService
{
private Tcp objSocket = new Tcp();
private NwConstants objConstants = new NwConstants();
public string Responses { get; set; }
private Timer timer1 = new Timer();
public TelnetService()
{
timer1.Elapsed += timer1_Elapsed;
timer1.Interval = 100;
timer1.Start();
}
void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (objSocket.ConnectionState == objConstants.nwSOCKET_CONNSTATE_CONNECTED)
{
if (objSocket.HasData())
{
Responses += objSocket.ReceiveString() + "\r\n";
}
}
}
public Task DoConnect(Node node)
{
return Task.Factory.StartNew(() =>
{
objSocket.Protocol = objConstants.nwSOCKET_PROTOCOL_TELNET;
objSocket.Connect(node.IP, 23);
while (true)
{
if ((Responses == null) || (!Responses.Contains(node.WaitString))) continue;
//do something
Responses = "";
break;
}
});
}
}
there are two important pieces of functionalities.
First in the timer1_Elapsed function which is process that will keeps on ruining and checks if there is data on socket, and if there is, it will append it to a string "Response". and i am using "timer" for it.
Second in the DoConnect function which will check the"Response" string for a certain input. for this i am using async await and Task.
in a nutshell first one accumulating the Response and Second one checking the Response.
Problem is that it looks like the timer code in general and
objSocket.ReceiveString()
line specifically is causing the UI thread to halt for several seconds. which means after clicking the button i cannot move my main form on the screen however the code is running in a separate thread.
i have tried using pure Thread for this but it didn't helped either.
update
instead of timer i am using a method AccumulateResponse
public static void AccumulateResponse()
{
while (true)
{
if (objSocket.ConnectionState == objConstants.nwSOCKET_CONNSTATE_CONNECTED)
{
if (objSocket.HasData())
{
Responses += objSocket.ReceiveString() + "\r\n";
}
}
}
}
and calling it like
var t = new Task(TelnetService.AccumulateResponse);
t.Start();
await TelnetService.DoConnect(node);
still no luck
The DoConnect isn't your problem. It is your Timer Elapsed Event handler.
The timer elapsed event is NOT asynchronous. Only the DoConnect is.
If there is no asynchronous version of ReceiveString() from your third party lib, then use Task.Run there as well inside of an async timer1_elapsed method.

How to avoid copy/paste many event handlers

My application cannot access a specific menu item unless some condition is true (DataRepository.IsAllDataLoaded). I came up with this code, which works great. It checks for the condition first. If it is not ready, it calls a timer, which waits some milliseconds and call the same method again. The Timer needs an ElapsedEventHandler.
public void FirstMenuItem_Click(object sender, RoutedEventArgs e)
{
if (!DataRepository.IsAllDataLoaded)
{
WaitForDataLoading(FirstTimedEvent);
}
else
{
Dispatcher.BeginInvoke(new Action(() =>
{
IndividualEntryWindow Window = new IndividualEntryWindow();
Window.Show();
}));
}
}
private void FirstTimedEvent(object source, ElapsedEventArgs e)
{
FirstMenuItem_Click(null, null);
}
private static void WaitForDataLoading(ElapsedEventHandler timerEvent)
{
Timer t = new Timer();
t.Interval = 0.2;
t.AutoReset = false;
t.Elapsed += new ElapsedEventHandler(timerEvent);
t.Start();
}
Initially, the FirstMenuItem_Click was the only method. I had to add FirstTimedEvent handler for my timer. Is there a way to avoid creating that ElapsedEventHandler? Can I create it inline in my FirstMenuItem_Click method?
I now have to use that same pattern for many other Item_Click methods. I wish I don't have to create a ElapsedEventHandler for each Item_Click method.
Use an anonymous lambda expression:
WaitForDataLoading((s,e) => FirstMenuItem_Click(null, null));
You appear to be using WPF, based on your use of the Dispatcher class. That being the case, there are nicer means for you to control the access to your UI.
Two of these are:
bind your menu's Enabled property to ViewModel class, which would have a property to indicate whether the menu should be available. When your long-running job is complete, set the property to true and the menu will be enabled.
use an ICommand to drive the behaviour of your menu. The command's CanExecute return false while your long-running job is active, which will cause the menu to automatically be disabled until the job is complete.
It's worth noting that this will subtly change the behaviour of your menu - but not, I think, in a bad way. Your current code will wait for the job to complete before showing the dialog - but there's nothing to stop the user clicking the menu again in the meantime. These multiple clicks will each wait for the job to complete, and each display their own dialog when the job completes. In a trivial case this might mean that I see multiple dialogs appear; in a severe case the multiple timers that you're creating might badly affect the performance of the application.
Either of the methods suggested above would prevent the menu from being clicked while the job is running, which is not quite your current behaviour but, I think, would make more sense from a usability perspective.
In the following code you can call the method CheckDataShowWindow() anytime you wish to show the windows when the data is ready. If you want to add it to another cick handler, you can just make another like so:
public void Another_Click(object sender, RoutedEventArgs e)
{
CheckDataShowWindow();
}
Main code:
public void FirstMenuItem_Click(object sender, RoutedEventArgs e)
{
CheckDataShowWindow();
}
private void CheckDataShowWindow()
{
if (!DataRepository.IsAllDataLoaded)
{
Timer t = new Timer();
t.Interval = 0.2;
t.AutoReset = false;
t.Elapsed += (s,e) => CheckDataShowWindow();
t.Start();
}
else
{
Dispatcher.BeginInvoke(new Action(() =>
{
IndividualEntryWindow Window = new IndividualEntryWindow();
Window.Show();
}));
}
}
Update
If you can edit the code of the datarepository you should add an event for when the data is done loading.
public delegate void DoneLoadingHandler(object sender, EventArgs e);
public class DataRepository
{
public event DoneLoadingHandler DoneLoading;
//Your loading function
private void LoadAllData()
{
//Load like you do now
//Now fire the event that loading is done.
if(DoneLoading != null)
DoneLoading(this, new EventArgs());
}
}
Now in your other class:
public void FirstMenuItem_Click(object sender, RoutedEventArgs e)
{
CheckDataShowWindow();
}
private bool AllReadyWaiting = false;
private void CheckDataShowWindow()
{
if (!DataRepository.IsAllDataLoaded)
{
if(!AllReadyWaiting)
{
DataRepository.DoneLoading += (s,e) => ShowWindow();
AllReadyWaiting = true;
}
}
else
{
ShowWindow();
}
}
private void ShowWindow()
{
Dispatcher.BeginInvoke(new Action(() =>
{
IndividualEntryWindow Window = new IndividualEntryWindow();
Window.Show();
}));
}

c# event handler being added twice

This is a fictional example but I was wandering what happens if the InitialiseTimer function gets called twice. Does the timer elapsed function get triggered twice. Will this change if the functions are made static?
private static void InitialiseTimer()
{
TheTimer = new System.Timers.Timer();
TheTimer.Interval = 400;
TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
TheTimer.AutoReset = false;
}
public void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Do stuff in here
}
I was going to use below to prevent this
Has an event handler already been added?
Thanks,
Richard
If you register the event handler twice, it will be invoked twice every time the event is raised.
This won't change if you make TheTimer_Elapsed static, because you'll still hold two references to this static method.
In most cases there's no need to write compicated things like what Blair Conrad posted in the question you linked to. Just don't forget to use -= every time you have += and you'll be safe.
I think the following demonstrates the scenario and does indeed fire twice, also propose a simple change (commented code) to the Init method that should fix the behavior. (Not thread safe btw, additional locks would be required)
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var counter = 0;
var ts = new ThreadStart(() =>
{
Foo.Fired += (o, e) =>
{
counter++;
};
Foo.InitialiseTimer();
Foo.InitialiseTimer();
});
var t = new Thread(ts);
t.Start();
Thread.Sleep(30);
Assert.AreEqual(1, counter);
}
}
public class Foo
{
private static System.Timers.Timer TheTimer = null;
public static event EventHandler Fired;
public static void InitialiseTimer()
{
//if (TheTimer != null)
//{
// TheTimer.Stop();
// TheTimer = null;
//}
TheTimer = new System.Timers.Timer();
TheTimer.Interval = 10;
TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
TheTimer.AutoReset = false;
TheTimer.Start();
}
public static void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Do stuff in here
if (Fired != null)
{
Fired(null, null);
}
}
}
if you call the method InitialiseTimer twice you will create two Timers each of them will have only one event handler attached but they might elapse both. It's not really about having the method static or not, it's more about the method itself, you could check if TheTimer is null and do the rest only if it's null so you assign it only once.
If event is registered twice you will have two executions.
You can check if event is null, and the problem will be solved.
Static or not, you are recreating the Timer. So you can invoke the InitialiseTimer many, many times without adding more than a single handler. You will end up with many timers though...

Is there a way to delay an event handler (say for 1 sec) in Windows Forms

I need to be able to delay the event handlers for some controls (like a button) to be fired for example after 1 sec of the actual event (click event for example) .. is this possible by the .net framework ?
I use a timer and call my code from the timer's tick event as below but I am not sure if this is the best approach !
void onButtonClick( ..)
{
timer1.Enabled = true;
}
void onTimerTick( ..)
{
timer.Enabled = false;
CallMyCodeNow();
}
Perhaps you could make a method that creates the timer?
void onButtonClick(object sender, EventArgs e)
{
Delay(1000, (o,a) => MessageBox.Show("Test"));
}
static void Delay(int ms, EventHandler action)
{
var tmp = new Timer {Interval = ms};
tmp.Tick += new EventHandler((o, e) => tmp.Enabled = false);
tmp.Tick += action;
tmp.Enabled = true;
}
Before coming to your question, just having read the summary bit from the main questions page, a timer was exactly what I was going to suggest.
This looks pretty clean to me. It means you can easily "cancel" the delayed event if you need to, by disabling the timer again, for example. It also does everything within the UI thread (but without reentrancy), which makes life a bit simpler than other alternatives might be.
If you're only doing this for one control, the timer approach will work fine. A more robust approach supporting multiple controls and types of events looks something like this:
class Event
{
public DateTime StartTime { get; set; }
public Action Method { get; set; }
public Event(Action method)
{
Method = method;
StartTime = DateTime.Now + TimeSpan.FromSeconds(1);
}
}
Maintain a Queue<Event> in your form and have UI events that need to be delayed add them to the queue, e.g.:
void onButtonClick( ..)
{
EventQueue.Enqueue(new Event(MethodToCall));
}
Make your timer tick 10 times a second or so, and have its Tick event handler look like this:
void onTimerTick()
{
if (EventQueue.Any() && EventQueue.First().StartTime >= DateTime.Now)
{
Event e = EventQueue.Dequeue();
e.Method;
}
}
My solution uses System.Threading.Timer:
public static class ExecuteWithDelay
{
class TimerState
{
public Timer Timer;
}
public static Timer Do(Action action, int dueTime)
{
var state = new TimerState();
state.Timer = new Timer(o =>
{
action();
lock (o) // The locking should prevent the timer callback from trying to free the timer prior to the Timer field having been set.
{
((TimerState)o).Timer.Dispose();
}
}, state, dueTime, -1);
return state.Timer;
}
}
For those limited to .NET 2.0, here is another take on Bengt's helpful solution:
/// <summary>
/// Executes the specified method in a delayed context by utilizing
/// a temporary timer.
/// </summary>
/// <param name="millisecondsToDelay">The milliseconds to delay.</param>
/// <param name="methodToExecute">The method to execute.</param>
public static void DelayedExecute(int millisecondsToDelay, MethodInvoker methodToExecute)
{
Timer timer = new Timer();
timer.Interval = millisecondsToDelay;
timer.Tick += delegate
{
// This will be executed on a single (UI) thread, so lock is not necessary
// but multiple ticks may have been queued, so check for enabled.
if (timer.Enabled)
{
timer.Stop();
methodToExecute.Invoke();
timer.Dispose();
}
};
timer.Start();
}
Using Reactive Extensions:
First, install the nuget package
PM> Install-Package Rx-Main
Code:
private void CallMyCodeNow()
{
label1.Text = "reactivated!";
}
private void Form1_Load(object sender, EventArgs e)
{
var o = Observable.FromEventPattern<EventHandler, EventArgs>(
handler => button1.Click += handler
, handler => button1.Click -= handler
)
.Delay(TimeSpan.FromSeconds(5))
.ObserveOn(SynchronizationContext.Current) // ensure event fires on UI thread
.Subscribe(
ev => CallMyCodeNow()
, ex => MessageBox.Show(ex.Message)
);
}
If you're looking for a more fancy solution, you may want to take a look at my Reactive LINQ project. The link doesn't show how to solve the particular problem you're having, but it should be possible to solve in quite an elegant style using the technique described there (in the whole 4-article series).
You can use:
Thread.Sleep(1000);
That will pause the current Thread for one second. So I would do that...
Best Regards!

Categories