Background Worker access from separate class - c#

I get an object reference is required for non-static field error when attempting to call OnProgressChanged and OnCheckCancel in separate class. It's a simple syntax error, but I can't figure it out.
I used the code from this link: BackgroundWorker cancellation
I can execute the code when the search engine code is included within the form, but I need to make it and many other methods in my class library support backgroundworkers.
//**** Windows Form code (Worker.cs)
public partial class Worker : Form
{
bwSearchEngine bwSE = new bwSearchEngine();
public Worker()
{
InitializeComponent();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
}
private void btnSearch_Click(object sender, EventArgs e)
{
// set arguments
bw.RunWorkerAsync(arguments);
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
bwSE.ProgressChanged += (s, pe) => worker.ReportProgress(pe.ProgressPercentage, pe.UserState);
bwSE.CheckCancel += (sender1, e1) => e1.Cancel = worker.CancellationPending;
e.Result = Search();
}
}
//**** Engine code (bwSearchEngine.cs)
public event ProgressChangedEventHandler ProgressChanged;
public event EventHandler<CancelEventArgs> CheckCancel;
protected virtual void OnProgressChanged(int progress, string message)
{
if (ProgressChanged != null)
{
ProgressChanged(this, new ProgressChangedEventArgs(progress, message));
}
}
protected virtual bool OnCheckCancel()
{
EventHandler<CancelEventArgs> handler = CheckCancel;
if (handler != null)
{
CancelEventArgs e = new CancelEventArgs();
handler(this, e);
return e.Cancel;
}
return false;
}
public class Extensions
{
public static List<HookSet> get_Extensions(string word, SQLiteDataSet hayfield)
{
foreach (DataRow dr ...)
{
// Do processing
if (results.Count > 0 && results.Count % 100 == 0)
{
OnProgressChanged(0, results.Count.ToString()); // ERROR ERROR
if (OnCheckCancel()) // ERROR ERROR
{
break;
}
}
}
}
return (results);
}

I found a (somewhat undesirable solution). The class method get_Extensions is a static method and it's not possible to call a non-static method OnProgressChanged() from that. If I make the latter a static method then I can't add events to it from the BackgroundWorker. So, it seems I have to make everything related non-static, and create an instance of the class before using it, ... until I can find a better solution.

I found a solution. I added the BackgroundWorker as a static method. Instead of adding the BackgroundWorker to the form in design mode, I added it to the constructor, and adjusted the code to accomodate the static bw.
private readonly static BackgroundWorker bw = new BackgroundWorker();
public Worker()
{
InitializeComponent();
bw.DoWork += new System.ComponentModel.DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;

Related

Silverlight ASync call of Service overriding class member

I'm using silverlight to access a webservice to request some data. This call is asynchronous. I (think I) have to put this data in a class member after doing some operations on it, so I can access it later.
public class CardPrinter
{
// The card to be printed
private UIElement printCard;
public void PrintStaffCard(string p_persoons)
{
Debug.WriteLine(p_persoons);
foreach (string persoon in p_persoons.Split(','))
{
int p_persoon = Convert.ToInt32(persoon.Trim());
this.GetStaffData(p_persoon);
}
}
private void GetStaffData(int p_persoon)
{
PictureServiceClient proxy = new PictureServiceClient();
proxy.GetPersonelCardInfoCompleted += this.Proxy_GetPersonelCardInfoCompleted;
proxy.GetPersonelCardInfoAsync(p_persoon);
}
private void Proxy_GetPersonelCardInfoCompleted(object sender, GetPersonelCardInfoCompletedEventArgs e)
{
if (e.Error != null)
{
Debug.WriteLine(e.Error.Message);
}
else
{
this.SendStaffCardToPrinter(e.Result);
}
}
private void SendStaffCardToPrinter(CardInfo.CardInfo card)
{
Canvas canvas = new Canvas()
//Do some stuff
this.printCard = canvas;
PrintDocument pd = new PrintDocument();
pd.PrintPage += new EventHandler<PrintPageEventArgs>(this.Pd_PrintPage);
pd.Print(card.accountNr, null, true);
}
private void Pd_PrintPage(object sender, PrintPageEventArgs e)
{
e.PageVisual = this.printCard;
}
}
The problem is in the printCard variable. Sometimes it still contains the data from a previous async call in the foreach.
If I could make sure that the call in the foreach is compeletely finished there would not be a problem, but not sure how to do this and if this is the correct way to handle this.
What is the best way to handle a situation like this?
You can make the code easier to use by using TaskCompletionSource to convert the asynchronous methods from event based to task based. Then you can get rid of the variable and usage of the methods becomes much like using a synchronous method.
I haven't tested this, but it should be close to what you need. You may also find the following article useful. And also the following post Nested Asynchronous function in Silverlight
public class CardPrinter
{
public void PrintStaffCard(string p_persoons)
{
Debug.WriteLine(p_persoons);
foreach (string persoon in p_persoons.Split(','))
{
int p_persoon = Convert.ToInt32(persoon.Trim());
var cardInfo = await this.GetStaffDataAsync(p_persoon);
await this.SendStaffCardToPrinterAsync(cardInfo);
}
}
private Task<CardInfo.CardInfo> GetStaffDataAsync(int p_persoon)
{
var tcs = new TaskCompletionSource<CardInfo.CardInfo>();
PictureServiceClient proxy = new PictureServiceClient();
proxy.GetPersonelCardInfoCompleted += (s, e) =>
{
if (e.Error != null)
{
Debug.WriteLine(e.Error.Message);
tcs.SetException(e.Error);
}
else
{
tcs.SetResult(e.Result);
}
};
proxy.GetPersonelCardInfoAsync(p_persoon);
return tcs.Task;
}
private Task SendStaffCardToPrinterAsync(CardInfo.CardInfo card)
{
Canvas canvas = new Canvas();
//Do some stuff
var tcs = new TaskCompletionSource<object>();
PrintDocument pd = new PrintDocument();
pd.PrintPage += (s, e) =>
{
e.PageVisual = canvas;
tcs.SetResult(null);
};
pd.Print(card.accountNr, null, true);
return tcs.Task;
}
}
The GetPersonalCardInfoAsync method should have an overload where you can pass a UserState argument. You can pass your printCard there when you're making the call and access it later in your Proxy_GetPersonelCardInfoCompleted.
private void GetStaffData(int p_persoon, UIElement printCard)
{
PictureServiceClient proxy = new PictureServiceClient();
proxy.GetPersonelCardInfoCompleted += this.Proxy_GetPersonelCardInfoCompleted;
proxy.GetPersonelCardInfoAsync(p_persoon, printCard);
}
private void Proxy_GetPersonelCardInfoCompleted(object sender, GetPersonelCardInfoCompletedEventArgs e)
{
UIElement printCard = (UIElement)e.UserState;
// do stuff
}

Should i pass a Backgroundworker to method

I have an app that has several methods that take a long time to complete. I am using a backgroundworker to run these methods and keep my UI responsive. My methods look something like
public void DoSomething()
{
while( HaveMoreWork )
{
// do work
}
}
Now i want the UI to be able to cancel this at any time so I have changed my methods to take a Backgroundworker like so
public void DoSomething(Backgroundworker worker)
{
while( HaveMoreWork && !worker.CancelationPending )
{
// do work
}
}
My question is, is there a better way to do this. Seems like passing a Backgroundwoker as an argument to all these methods is a bit messy. What is best practice for this?
I am using global variable
private BackgroundWorker _bwSearch = new BackgroundWorker();
private void InitializeBackgroundWorker()
{
_bwSearch = new BackgroundWorker();
_bwSearch.WorkerSupportsCancellation = true;
_bwSearch.DoWork += bwSearch_DoWork;
_bwSearch.RunWorkerCompleted += bwSearch_RunWorkerCompleted;
}
when clicked on stop button
private void btnCancel_Click(object sender, EventArgs e)
{
_bwSearch.Abort();
}
Updated:
Also I am using this simple helper class that is inherited from BackgroundWorker
public class AbortableBackgroundWorker : BackgroundWorker
{
private Thread _workerThread;
protected override void OnDoWork(DoWorkEventArgs e)
{
_workerThread = Thread.CurrentThread;
try
{
base.OnDoWork(e);
}
catch (ThreadAbortException)
{
e.Cancel = true;
Thread.ResetAbort();
}
}
public void Abort()
{
if (_workerThread != null)
{
_workerThread.Abort();
_workerThread = null;
}
}
}
public class DoSomethingService
{
private volatile bool _stopped = false;
public void Start(object socketQueueObject)
{
while (!_stopped)
{
...
}
}
public void Stop()
{
_stopped = true;
}
}
...
var doSomethingService = DoSomethingService();
doSomethingService.Start();
...
doSomethingService.Stop();

Question on threading in C#

I have a Windows Forms application at the moment, and I want to create a new thread and run a method on another class that accepts an input.
For example
public partial class Form1: Form {
SerialPort serialInput;
// I want to create a new thread that will pass the parameter serialInput into the method
// SMSListener on another class and run the method contionously on the background.
}
class SMS
{
public void SMSListener(SerialPort serial1)
{
serial1.DataReceived += port_DataRecieved;
}
private void port_DataRecieved(object sender, SerialDataReceivedEventArgs e)
{
// Other codes
}
}
How do I perform this in C#? I have seen numerous examples on the web, and most of them run the method on the same class with no parameters, but none that suits my requirements.
Perhaps a Background Worker could help you?
It is a bit hard to understand what you are aiming at.
public class Runner
{
private readonly BackgroundWorker _worker = new BackgroundWorker();
public Runner()
{
_worker.DoWork += WorkerDoWork;
}
public void RunMe(int payload)
{
_worker.RunWorkerAsync(payload);
}
static void WorkerDoWork(object sender, DoWorkEventArgs e)
{
var worker = sender as BackgroundWorker;
while (true)
{
if (worker.CancellationPending)
{
e.Cancel = true;
break;
}
// Work
System.Threading.Thread.Sleep((int)e.Argument);
}
}
}
I am not an expert on Multithreading but to the best of my knowledge you can only start threads on methods that accept an object parameter and return void. So in order to achieve that for your problem (don't shoot me down if there is a better approach!) I would do something like
public partial class Form1: Form {
SerialPort serialInput;
// I want to create a new thread that will pass the parameter serialInput into the method
// SMSListener on another class and run the method contionously on the background.
SMS sms = new SMS();
Thread t = new Thread(sms.SMSListenerUntyped);
t.Start(serialInput);
}
class SMS
{
public void SMSListenerUntyped(object serial1) {
if (serial1 is SerialPort) //Check if the parameter is correctly typed.
this.SMSListener(serial1 as SerialPort);
else
throw new ArgumentException();
}
public void SMSListener(SerialPort serial1)
{
serial1.DataReceived += port_DataRecieved;
}
private void port_DataRecieved(object sender, SerialDataReceivedEventArgs e)
{
// Other code.
}
How about just use the ThreadPool directly with a anonymous method allowing you to access your surrounding locals?
public void OnButtonClick(object sender, EventArgs e)
{
SerialPort serialInput = this.SerialInput;
System.Threading.ThreadPool.QueueUserWorkItem(delegate
{
SmsListener listener = new SmsListener(serialInput);
});
}

How to unit test this library?

I have an external library which has a method which performs a long running task on a background thread. When it's done it fires off a Completed event on the thread that kicked off the method (typically the UI thread). It looks like this:
public class Foo
{
public delegate void CompletedEventHandler(object sender, EventArgs e);
public event CompletedEventHandler Completed;
public void LongRunningTask()
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(5000);
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (Completed != null)
Completed(this, EventArgs.Empty);
}
}
The code that calls this library looks like this:
private void button1_Click(object sender, EventArgs e)
{
Foo b = new Foo();
b.Completed += new Foo.CompletedEventHandler(b_Completed);
b.LongRunningTask();
Debug.WriteLine("It's all done");
}
void b_Completed(object sender, EventArgs e)
{
// do stuff
}
How do I unit test the call to .LongRunningTask given that it returns data in an event?
I'm not sure if I got it right. Do you want to check the external library if it fires the event? Or do you want to check that you do something particularly if the event is fired?
If it is the latter, I would use a mock for that. The problem is though, that your code seems to be hard to test, because you're doing logical stuff in the user interface. Try to write a "passive" view, and let a presenter do the magic. For example by using the Model View Presenter pattern http://msdn.microsoft.com/en-us/magazine/cc188690.aspx
The whole thing would then look like this.
The Model
public class Model : IModel
{
public event EventHandler<SampleEventArgs> Completed;
public void LongRunningTask()
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += this.bw_DoWork;
bw.RunWorkerCompleted += this.bw_RunWorkerCompleted;
bw.RunWorkerAsync();
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (this.Completed != null)
{
this.Completed(this, new SampleEventArgs {Data = "Test"});
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(5000);
}
}
The View
public Form1()
{
InitializeComponent();
}
public event EventHandler Button1Clicked;
public void Update(string data)
{
this.label1.Text = data;
}
private void Button1Click(object sender, EventArgs e)
{
if (this.Button1Clicked != null)
{
this.Button1Clicked(this, EventArgs.Empty);
}
}
The Presenter
public class Presenter
{
private readonly IForm1 form1;
private readonly IModel model;
public Presenter(IForm1 form1, IModel model)
{
this.form1 = form1;
this.model = model;
this.form1.Button1Clicked += this.Form1Button1Clicked;
this.model.Completed += this.ModelCompleted;
}
private void ModelCompleted(object sender, SampleEventArgs e)
{
this.form1.Update(e.Data);
}
private void Form1Button1Clicked(object sender, EventArgs e)
{
this.model.LongRunningTask();
}
}
Somewhere you assemble it (e.g. in the Program class)
var form = new Form1();
var model = new Model();
var presenter = new Presenter(form, model);
Application.Run(form);
And then you can easily just test the presenter in an unit test. The part in the gui is now little enough to not be tested.
The possible test could look like this
[Test]
public void Test()
{
var form1Mock = new Mock<IForm1>();
var modelMock = new Mock<IModel>();
var presenter = new Presenter(form1Mock.Object, modelMock.Object);
modelMock.Setup(m => m.LongRunningTask()).Raises(m => m.Completed += null, new SampleEventArgs() { Data = "Some Data" });
form1Mock.Raise(f => f.Button1Clicked += null, EventArgs.Empty);
form1Mock.Verify(f => f.Update("Some Data"));
}
Well, I believe BackgroundWorker uses the current SynchronizationContext. You could potentially implement your own subclass of SynchronizationContext to allow you more control (possibly even running code on the same thread, although that will break anything which depends on it running in a different thread) and call SetSynchronizationContext before running the test.
You'd need to subscribe to the event in your test, and then check whether or not your handler was called. (Lambda expressions are good for this.)
For example, suppose you have a SynchronizationContext which lets you run all the work only when you want it to, and tell you when it's done, your test might:
Set the synchronization context
Create the component
Subscribe to the handler with a lambda which sets a local variable
Call LongRunningTask()
Verify that the local variable hasn't been set yet
Make the synchronization context do all its work... wait until it's finished (with a timeout)
Verify that the local variable has now been set
It's all a bit nasty, admittedly. If you can just test the work it's doing, synchronously, that would be a lot easier.
You can create an extension method that can help with turning it into a synchronous call. You can make tweaks like making it more generic and passing in the timeout variable but at least it will make the unit test easier to write.
static class FooExtensions
{
public static SomeData WaitOn(this Foo foo, Action<Foo> action)
{
SomeData result = null;
var wait = new AutoResetEvent(false);
foo.Completed += (s, e) =>
{
result = e.Data; // I assume this is how you get the data?
wait.Set();
};
action(foo);
if (!wait.WaitOne(5000)) // or whatever would be a good timeout
{
throw new TimeoutException();
}
return result;
}
}
public void TestMethod()
{
var foo = new Foo();
SomeData data = foo.WaitOn(f => f.LongRunningTask());
}
For testing asynchronous code I use a similar helper:
public class AsyncTestHelper
{
public delegate bool TestDelegate();
public static bool AssertOrTimeout(TestDelegate predicate, TimeSpan timeout)
{
var start = DateTime.Now;
var now = DateTime.Now;
bool result = false;
while (!result && (now - start) <= timeout)
{
Thread.Sleep(50);
now = DateTime.Now;
result = predicate.Invoke();
}
return result;
}
}
In the test method then call something like this:
Assert.IsTrue(AsyncTestHelper.AssertOrTimeout(() => changeThisVarInCodeRegisteredToCompletedEvent, TimeSpan.FromMilliseconds(500)));

Blocking and waiting for an event

It sometimes want to block my thread while waiting for a event to occur.
I usually do it something like this:
private AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
private void OnEvent(object sender, EventArgs e){
_autoResetEvent.Set();
}
// ...
button.Click += OnEvent;
try{
_autoResetEvent.WaitOne();
}
finally{
button.Click -= OnEvent;
}
However, it seems that this should be something that I could extract to a common class (or perhaps even something that already exists in the framework).
I would like to be able to do something like this:
EventWaiter ew = new EventWaiter(button.Click);
ew.WaitOne();
EventWaiter ew2 = new EventWaiter(form.Closing);
ew2.WaitOne();
But I can't really find a way to construct such a class (I can't find a good valid way to pass the event as an argument). Can anyone help?
To give an example of why this can be useful, consider something like this:
var status = ShowStatusForm();
status.ShowInsertUsbStick();
bool cancelled = WaitForUsbStickOrCancel();
if(!cancelled){
status.ShowWritingOnUsbStick();
WriteOnUsbStick();
status.AskUserToRemoveUsbStick();
WaitForUsbStickToBeRemoved();
status.ShowFinished();
}else{
status.ShowCancelled();
}
status.WaitUntilUserPressesDone();
This is much more concise and readable than the equivalent code written with the logic spread out between many methods. But to implement WaitForUsbStickOrCancel(), WaitForUsbStickToBeRemoved and WaitUntilUserPressesDone() (assume that the we get an event when usb sticks are inserted or removed) I need to reimplement "EventWaiter" each time. Of course you have to be careful to never run this on the GUI-thread, but sometimes that is a worthwhile tradeoff for the simpler code.
The alternative would look something like this:
var status = ShowStatusForm();
status.ShowInsertUsbStick();
usbHandler.Inserted += OnInserted;
status.Cancel += OnCancel;
//...
void OnInserted(/*..*/){
usbHandler.Inserted -= OnInserted;
status.ShowWritingOnUsbStick();
MethodInvoker mi = () => WriteOnUsbStick();
mi.BeginInvoke(WritingDone, null);
}
void WritingDone(/*..*/){
/* EndInvoke */
status.AskUserToRemoveUsbStick();
usbHandler.Removed += OnRemoved;
}
void OnRemoved(/*..*/){
usbHandler.Removed -= OnRemoved;
status.ShowFinished();
status.Done += OnDone;
}
/* etc */
I find that much harder to read. Admittedly, it is far from always that the flow will be so linear, but when it is, I like the first style.
It is comparable to using ShowMessage() and Form.ShowDialog() - they also block until some "event" occurs (though they will run a message-loop if they are called on the gui-thread).
I modified Dead.Rabit's class EventWaiter to handle EventHandler<T>. So you can use for waiting all events type of EventHandler<T>, that means your delegate is something like delegate void SomeDelegate(object sender, T EventsArgs).
public class EventWaiter<T>
{
private AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
private EventInfo _event = null;
private object _eventContainer = null;
public EventWaiter(object eventContainer, string eventName)
{
_eventContainer = eventContainer;
_event = eventContainer.GetType().GetEvent(eventName);
}
public void WaitForEvent(TimeSpan timeout)
{
EventHandler<T> eventHandler = new EventHandler<T>((sender, args) => { _autoResetEvent.Set(); });
_event.AddEventHandler(_eventContainer, eventHandler);
_autoResetEvent.WaitOne(timeout);
_event.RemoveEventHandler(_eventContainer, eventHandler);
}
}
And for example I use that for waiting to get Url from HttpNotificationChannel when I registering to windows push notification service.
HttpNotificationChannel pushChannel = new HttpNotificationChannel(channelName);
//ChannelUriUpdated is event
EventWaiter<NotificationChannelUriEventArgs> ew = new EventWaiter<NotificationChannelUriEventArgs>(pushChannel, "ChannelUriUpdated");
pushChannel.Open();
ew.WaitForEvent(TimeSpan.FromSeconds(30));
Don't pass the event, pass a delegate that matches the event handler signature. This actually sounds hacky to me, so be aware of potential dead lock issues.
I've rushed together a working sample in LinqPad using reflection, getting a reference to the EventInfo object with a string (be careful as you loose compile time checking). The obvious issue is that there is no guarentee an event will ever be fired, or that the event your expecting may be fired before the EventWaiter class is ready to start blocking so I'm not sure I'd sleep comfy if I put this in a production app.
void Main()
{
Console.WriteLine( "main thread started" );
var workerClass = new WorkerClassWithEvent();
workerClass.PerformWork();
var waiter = new EventWaiter( workerClass, "WorkCompletedEvent" );
waiter.WaitForEvent( TimeSpan.FromSeconds( 10 ) );
Console.WriteLine( "main thread continues after waiting" );
}
public class WorkerClassWithEvent
{
public void PerformWork()
{
var worker = new BackgroundWorker();
worker.DoWork += ( s, e ) =>
{
Console.WriteLine( "threaded work started" );
Thread.Sleep( 1000 ); // <= the work
Console.WriteLine( "threaded work complete" );
};
worker.RunWorkerCompleted += ( s, e ) =>
{
FireWorkCompletedEvent();
Console.WriteLine( "work complete event fired" );
};
worker.RunWorkerAsync();
}
public event Action WorkCompletedEvent;
private void FireWorkCompletedEvent()
{
if ( WorkCompletedEvent != null ) WorkCompletedEvent();
}
}
public class EventWaiter
{
private AutoResetEvent _autoResetEvent = new AutoResetEvent( false );
private EventInfo _event = null;
private object _eventContainer = null;
public EventWaiter( object eventContainer, string eventName )
{
_eventContainer = eventContainer;
_event = eventContainer.GetType().GetEvent( eventName );
}
public void WaitForEvent( TimeSpan timeout )
{
_event.AddEventHandler( _eventContainer, (Action)delegate { _autoResetEvent.Set(); } );
_autoResetEvent.WaitOne( timeout );
}
}
Output
// main thread started
// threaded work started
// threaded work complete
// work complete event fired
// main thread continues after waiting
You may also try this:
class EventWaiter<TEventArgs> where TEventArgs : EventArgs
{
private readonly Action<EventHandler<TEventArgs>> _unsubHandler;
private readonly Action<EventHandler<TEventArgs>> _subHandler;
public EventWaiter(Action<EventHandler<TEventArgs>> subHandler, Action<EventHandler<TEventArgs>> unsubHandler)
{
_unsubHandler = unsubHandler;
_subHandler = subHandler;
}
protected void Handler(object sender, TEventArgs args)
{
_unsubHandler.Invoke(Handler);
TaskCompletionSource.SetResult(args);
}
public TEventArgs WaitOnce()
{
TaskCompletionSource = new TaskCompletionSource<TEventArgs>();
_subHandler.Invoke(Handler);
return TaskCompletionSource.Task.Result;
}
protected TaskCompletionSource<TEventArgs> TaskCompletionSource { get; set; }
}
Usage:
EventArgs eventArgs = new EventWaiter<EventArgs>((h) => { button.Click += new EventHandler(h); }, (h) => { button.Click -= new EventHandler(h); }).WaitOnce();
I think like these should work, didn't tried just coded.
public class EventWaiter<T> where T : EventArgs
{
private System.Threading.ManualResetEvent manualEvent;
public EventWaiter(T e)
{
manualEvent = new System.Threading.ManualResetEvent(false);
e += this.OnEvent;
}
public void OnEvent(object sender, EventArgs e)
{
manualEvent.Set();
}
public void WaitOne()
{
manualEvent.WaitOne();
}
public void Reset()
{
manualEvent.Reset();
}
}
Didn't thought about too much, but can't figure out how to make it isolated from the EventArgs.
Take a look at the MSDN ManualResetEvent and you will discover that you can kind of chain the waits and so some weird stuff.

Categories