Raising C# events with an extension method - is it bad? - c#

We're all familiar with the horror that is C# event declaration. To ensure thread-safety, the standard is to write something like this:
public event EventHandler SomethingHappened;
protected virtual void OnSomethingHappened(EventArgs e)
{
var handler = SomethingHappened;
if (handler != null)
handler(this, e);
}
Recently in some other question on this board (which I can't find now), someone pointed out that extension methods could be used nicely in this scenario. Here's one way to do it:
static public class EventExtensions
{
static public void RaiseEvent(this EventHandler #event, object sender, EventArgs e)
{
var handler = #event;
if (handler != null)
handler(sender, e);
}
static public void RaiseEvent<T>(this EventHandler<T> #event, object sender, T e)
where T : EventArgs
{
var handler = #event;
if (handler != null)
handler(sender, e);
}
}
With these extension methods in place, all you need to declare and raise an event is something like this:
public event EventHandler SomethingHappened;
void SomeMethod()
{
this.SomethingHappened.RaiseEvent(this, EventArgs.Empty);
}
My question: Is this a good idea? Are we missing anything by not having the standard On method? (One thing I notice is that it doesn't work with events that have explicit add/remove code.)

It will still work with events that have an explicit add/remove - you just need to use the delegate variable (or however you've stored the delegate) instead of the event name.
However, there's an easier way to make it thread-safe - initialize it with a no-op handler:
public event EventHandler SomethingHappened = delegate {};
The performance hit of calling an extra delegate will be negligible, and it sure makes the code easier.
By the way, in your extension method you don't need an extra local variable - you could just do:
static public void RaiseEvent(this EventHandler #event, object sender, EventArgs e)
{
if (#event != null)
#event(sender, e);
}
static public void RaiseEvent<T>(this EventHandler<T> #event, object sender, T e)
where T : EventArgs
{
if (#event != null)
#event(sender, e);
}
Personally I wouldn't use a keyword as a parameter name, but it doesn't really change the calling side at all, so do what you want :)
EDIT: As for the "OnXXX" method: are you planning on your classes being derived from? In my view, most classes should be sealed. If you do, do you want those derived classes to be able to raise the event? If the answer to either of these questions is "no" then don't bother. If the answer to both is "yes" then do :)

Now C# 6 is here, there is a more compact, thread-safe way to fire an event:
SomethingHappened?.Invoke(this, e);
Invoke() is only called if delegates are registered for the event (i.e. it's not null), thanks to the null-conditional operator, "?".
The threading problem the "handler" code in the question sets out to solve is sidestepped here because, like in that code, SomethingHappened is only accessed once, so there is no possibility of it being set to null between test and invocation.
This answer is perhaps tangential to the original question, but very relevent for those looking for a simpler method to raise events.

[Here's a thought]
Just write the code once in the recommended way and be done with it. Then you won't confuse your colleagues looking over the code thinking you did something wrong?
[I read more posts trying to find ways around writing an event handler than I ever spend writing an event handler.]

Less code, more readable. Me like.
If you're not interested in performance you can declare your event like this to avoid the null check:
public event EventHandler SomethingHappened = delegate{};

You're not "ensuring" thread safety by assigning the handler to a local variable. Your method could still be interrupted after the assignment. If for example the class that used to listen for the event gets disposed during the interruption, you're calling a method in a disposed class.
You're saving yourself from a null reference exception, but there are easier ways to do that, as Jon Skeet and cristianlibardo pointed out in their answers.
Another thing is that for non-sealed classes, the OnFoo method should be virtual which I don't think is possible with extension methods.

To take the above answers a step further you could protect yourself against one of your handlers throwing an exception. If this were to happen then the subsequent handlers wouldn't be called.
Likewise, you could taskify the handlers to prevent a long-running handler from causing an excessive delay for the latter handlers to be informed. This can also protect the source thread from being hijacked by a long-running handler.
public static class EventHandlerExtensions
{
private static readonly log4net.ILog _log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public static void Taskify(this EventHandler theEvent, object sender, EventArgs args)
{
Invoke(theEvent, sender, args, true);
}
public static void Taskify<T>(this EventHandler<T> theEvent, object sender, T args)
{
Invoke(theEvent, sender, args, true);
}
public static void InvokeSafely(this EventHandler theEvent, object sender, EventArgs args)
{
Invoke(theEvent, sender, args, false);
}
public static void InvokeSafely<T>(this EventHandler<T> theEvent, object sender, T args)
{
Invoke(theEvent, sender, args, false);
}
private static void Invoke(this EventHandler theEvent, object sender, EventArgs args, bool taskify)
{
if (theEvent == null)
return;
foreach (EventHandler handler in theEvent.GetInvocationList())
{
var action = new Action(() =>
{
try
{
handler(sender, args);
}
catch (Exception ex)
{
_log.Error(ex);
}
});
if (taskify)
Task.Run(action);
else
action();
}
}
private static void Invoke<T>(this EventHandler<T> theEvent, object sender, T args, bool taskify)
{
if (theEvent == null)
return;
foreach (EventHandler<T> handler in theEvent.GetInvocationList())
{
var action = new Action(() =>
{
try
{
handler(sender, args);
}
catch (Exception ex)
{
_log.Error(ex);
}
});
if (taskify)
Task.Run(action);
else
action();
}
}
}

Related

EventHandler with Task as return value

The base C# EventHandler is defined as:
namespace System
{
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
}
Does anyone if there is an awaitable event handler available? E.g.
public delegate Task EventHandlerAsnyc<TEventArgs>(object sender, TEventArgs e);
Thx
If you want your event to be processed async (meaning you can use await to return early and resume later) you can simply declare the handler as async void:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponents();
myButton.Click += myButton_Click;
}
public async void myButton_Click(object sender, EventArgs e)
{
myButton.Enabled = false;
await SomeAsyncOrLongRunningOnAnotherThreadTask();
myButton.Enabled = true;
}
}
This way SomeAsyncOrLongRunningOnAnotherThreadTask() won't block your UI thread. And the handler is resumed after that task completes.
Side note: normally async methods should always return a Task or Task<T> that can be awaited or otherwise handled by the caller. The use case above is (afaik) the only justified case where void should be used for an async method.
The downside of just using async void handlers is that there is no way for the caller to wait for the result. This may be an issue for some interactive event handlers, like the ones using CancelEventArgs.
But you can still declare a Task-returning delegate type, if you wish. You just have to be careful how you raise it then. For instance, you could make an extension method which you can call as handler.Raise(sender, EventArgs.Empty).
public delegate Task EventHandlerAsnyc<TEventArgs>(object sender, TEventArgs eventArgs);
public static async Task Raise<TEventArgs>(this EventHandlerAsnyc<TEventArgs> handlers, object sender, TEventArgs eventArgs)
{
if (handlers == null)
return;
foreach (var handler in handlers.GetInvocationList())
await ((EventHandlerAsnyc<TEventArgs>)handler).Invoke(sender, eventArgs);
}
Alternatively, you can allow handlers to execute concurrently. But this would probably be a bad idea unless well-documented, as it's probably considered surprising behavior.
public static Task RaiseAllowConcurrent<TEventArgs>(this EventHandlerAsnyc<TEventArgs> handlers, object sender, TEventArgs eventArgs)
{
if (handlers == null)
return Task.CompletedTask;
var invocationList = handlers.GetInvocationList();
var tasks = new Task[invocationList.Length];
for (var i = 0; i < invocationList.Length; ++i)
tasks[i] = ((EventHandlerAsnyc<TEventArgs>)invocationList[i]).Invoke(sender, eventArgs);
return Task.WhenAll(tasks);
}

Unit testing async void event handler

I have implemented the MVP (MVC) pattern in c# winforms.
My View and Presenter are as follows (without all the MVP glue):
public interface IExampleView
{
event EventHandler<EventArgs> SaveClicked;
string Message {get; set; }
}
public partial class ExampleView : Form
{
public event EventHandler<EventArgs> SaveClicked;
string Message {
get { return txtMessage.Text; }
set { txtMessage.Text = value; }
}
private void btnSave_Click(object sender, EventArgs e)
{
if (SaveClicked != null) SaveClicked.Invoke(sender, e);
}
}
public class ExamplePresenter
{
public void OnLoad()
{
View.SaveClicked += View_SaveClicked;
}
private async void View_SaveClicked(object sender, EventArgs e)
{
await Task.Run(() =>
{
// Do save
});
View.Message = "Saved!"
}
I am using MSTest for unit testing, along with NSubstitute for mocking. I want to simulate a button click in the view to test the controller's View_SaveClicked code as have the following:
[TestMethod]
public void WhenSaveButtonClicked_ThenSaveMessageShouldBeShown()
{
// Arrange
// Act
View.SaveClicked += Raise.EventWith(new object(), new EventArgs());
// Assert
Assert.AreEqual("Saved!", View.Message);
}
I am able to raise the View.SaveClicked successfully using NSubstitute's Raise.EventWith. However, the problem is that code immediately proceeds to the Assert before the Presenter has had time to save the message and the Assert fails.
I understand why this is happening and have managed to get around it by adding a Thread.Sleep(500) before the Assert, but this is less than ideal. I could also update my view to call a presenter.Save() method instead, but I would like the View to be Presenter agnostic as much as possible.
So would like to know I can improve the unit test to either wait for the async View_SaveClicked to finish or change the View/Presenter code to allow them to be unit tested easier in this situation.
Any ideas?
Since you are just concerned about unit testing, then you can use a custom SynchronizationContext, which allows you to detect the completion of async void methods.
You can use my AsyncContext type for this:
[TestMethod]
public void WhenSaveButtonClicked_ThenSaveMessageShouldBeShown()
{
// Arrange
AsyncContext.Run(() =>
{
// Act
View.SaveClicked += Raise.EventWith(new object(), new EventArgs());
});
// Assert
Assert.AreEqual("Saved!", View.Message);
}
However, it's best to avoid async void in your own code (as I describe in an MSDN article on async best practices). I have a blog post specifically about a few approaches on "async event handlers".
One approach is to replace all EventHandler<T> events with plain delegates, and call it via await:
public Func<Object, EventArgs, Task> SaveClicked;
private void btnSave_Click(object sender, EventArgs e)
{
if (SaveClicked != null) await SaveClicked(sender, e);
}
This is less pretty if you want a real event, though:
public delegate Task AsyncEventHandler<T>(object sender, T e);
public event AsyncEventHandler<EventArgs> SaveClicked;
private void btnSave_Click(object sender, EventArgs e)
{
if (SaveClicked != null)
await Task.WhenAll(
SaveClicked.GetInvocationList().Cast<AsyncEventHandler<T>>
.Select(x => x(sender, e)));
}
With this approach, any synchronous event handlers would need to return Task.CompletedTask at the end of the handler.
Another approach is to extend the EventArgs with a "deferral". This is also not pretty, but is more idiomatic for asynchronous event handlers.
There must be a some type work being done of the running task, and you need to use something to return a value from the task.
Seems like the Thread.Sleep helps mitigate that, though, might help to add some logic, and get a value from the task.
From: https://msdn.microsoft.com/en-us/library/mt674882.aspx

Subscribing and unsubscribing from a method instead of a delegate?

I know there are times you need to keep track of a delegate so that it can be unsubscribed properly:
private EventHandler _handler;
public void Foo()
{
if (_handler != null)
{
Something.SomeEvent -= _handler; // Unsubscribe old event
}
_handler = delegate(object sender, EventArgs args) { };;
Something.SomeEvent += _handler;
}
But, is that still necessary if you use a method instead?
public void CustomMethod(object sender, EventArgs args) { ... }
public void Foo()
{
// Not sure how to unsubscribe only if it wasn't subscribed first?
if (some way to check)
{
Something.SomeEvent -= CustomMethod;
}
Something.SomeEvent += CustomMethod;
}
No, it's not necessary. If you are always subscribing/unsubscribing the same method (in the form of a delegate), then you don't need to track the actual delegate instance that was subscribed. The new delegate instances (implicitly created for you by the C# compiler in the += and -= operations) are correctly identified as identical, so that the -= operation removes the delegate that was added in the += operation.
In other words, equality for the Delegate class is not just "reference equality". Two completely different Delegate instances that have the same invocation list are considered equal.
If you wanna check if a specific method subscribed or not you can use GetInvocationList and then Linq:
var mInfo = typeof(SomeType).GetMethod("CustomMethod");
if(Something.SomeEvent.GetInvocationList().Any(x => x.Method == mInfo))
{
}

One shot events using Lambda in C#

I find myself doing this sort of thing quite often:-
EventHandler eh = null; //can't assign lambda directly since it uses eh
eh = (s, args) =>
{
//small snippet of code here
((SomeType)s).SomeEvent -= eh;
}
variableOfSomeType.SomeEvent += eh;
Basically I only want to attach an event handler to listen for one shot from the event, I no longer want to stay attached after that. Quite often that "snippert of code" is just one line.
My mind is going a bit numb, I'm sure there must be something I can do so I don't need to repeat all this overhead. Bear in mind that EventHandler may well be EventHandler<T>.
Any ideas how I can tidy up the repeative part of the code and just leave the snippet in a Lambda?
You could attache a permanent event handler to the event. The event handler then invokes "one shot event handlers" that are added to an internal queue:
OneShotHandlerQueue<EventArgs> queue = new OneShotHandlerQueue<EventArgs>();
Test test = new Test();
// attach permanent event handler
test.Done += queue.Handle;
// add a "one shot" event handler
queue.Add((sender, e) => Console.WriteLine(e));
test.Start();
// add another "one shot" event handler
queue.Add((sender, e) => Console.WriteLine(e));
test.Start();
Code:
class OneShotHandlerQueue<TEventArgs> where TEventArgs : EventArgs {
private ConcurrentQueue<EventHandler<TEventArgs>> queue;
public OneShotHandlerQueue() {
this.queue = new ConcurrentQueue<EventHandler<TEventArgs>>();
}
public void Handle(object sender, TEventArgs e) {
EventHandler<TEventArgs> handler;
if (this.queue.TryDequeue(out handler) && (handler != null))
handler(sender, e);
}
public void Add(EventHandler<TEventArgs> handler) {
this.queue.Enqueue(handler);
}
}
Test class:
class Test {
public event EventHandler Done;
public void Start() {
this.OnDone(new EventArgs());
}
protected virtual void OnDone(EventArgs e) {
EventHandler handler = this.Done;
if (handler != null)
handler(this, e);
}
}
You can use reflection:
public static class Listener {
public static void ListenOnce(this object eventSource, string eventName, EventHandler handler) {
var eventInfo = eventSource.GetType().GetEvent(eventName);
EventHandler internalHandler = null;
internalHandler = (src, args) => {
eventInfo.RemoveEventHandler(eventSource, internalHandler);
handler(src, args);
};
eventInfo.AddEventHandler(eventSource, internalHandler);
}
public static void ListenOnce<TEventArgs>(this object eventSource, string eventName, EventHandler<TEventArgs> handler) where TEventArgs : EventArgs {
var eventInfo = eventSource.GetType().GetEvent(eventName);
EventHandler<TEventArgs> internalHandler = null;
internalHandler = (src, args) => {
eventInfo.RemoveEventHandler(eventSource, internalHandler);
handler(src, args);
};
eventInfo.AddEventHandler(eventSource, internalHandler);
}
}
Use it like so:
variableOfSomeType.ListenOnce("SomeEvent",
(s, args) => Console.WriteLine("I should print only once!"));
variableOfSomeType.ListenOnce<InterestingEventArgs>("SomeOtherEvent",
(s, args) => Console.WriteLine("I should print only once!"));
If you can use the Reactive Extensions for .NET, you can simplify this.
You can make an Observable from an event, and only listen for the first element using .Take(1), to do your small snippet of code. This turns this entire process into a couple of lines of code.
Edit: In order to demonstrate, I've made a full sample program (I'll paste below).
I moved the observable creation and subscription into a method (HandleOneShot). This lets you do what you're attempting with a single method call. For demonstrating, I made a class with two properties that implements INotifyPropertyChanged, and am listening for the first property changed event, writing to the console when it occurs.
This takes your code, and changes it to:
HandleOneShot<SomeEventArgs>(variableOfSomeType, "SomeEvent", e => {
// Small snippet of code here
});
Notice that all of the subscription/unsubscription happens automatically for you behind the scenes. There's no need to handle putting in the subscription manually - just Subscribe to the Observable, and Rx takes care of this for you.
When run, this code prints:
Setup...
Setting first property...
**** Prop2 Changed! /new val
Setting second property...
Setting first property again.
Press ENTER to continue...
You only get a single, one shot trigger of your event.
namespace ConsoleApplication1
{
using System;
using System.ComponentModel;
using System.Linq;
class Test : INotifyPropertyChanged
{
private string prop2;
private string prop;
public string Prop
{
get {
return prop;
}
set
{
if (prop != value)
{
prop = value;
if (PropertyChanged!=null)
PropertyChanged(this, new PropertyChangedEventArgs("Prop"));
}
}
}
public string Prop2
{
get
{
return prop2;
}
set
{
if (prop2 != value)
{
prop2 = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Prop2"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
class Program
{
static void HandleOneShot<TEventArgs>(object target, string eventName, Action<TEventArgs> action) where TEventArgs : EventArgs
{
var obsEvent = Observable.FromEvent<TEventArgs>(target, eventName).Take(1);
obsEvent.Subscribe(a => action(a.EventArgs));
}
static void Main(string[] args)
{
Test test = new Test();
Console.WriteLine("Setup...");
HandleOneShot<PropertyChangedEventArgs>(
test,
"PropertyChanged",
e =>
{
Console.WriteLine(" **** {0} Changed! {1}/{2}!", e.PropertyName, test.Prop, test.Prop2);
});
Console.WriteLine("Setting first property...");
test.Prop2 = "new value";
Console.WriteLine("Setting second property...");
test.Prop = "second value";
Console.WriteLine("Setting first property again...");
test.Prop2 = "other value";
Console.WriteLine("Press ENTER to continue...");
Console.ReadLine();
}
}
}
Another user encountered a very similar problem, and I believe the solution in that thread applies here.
In particular, what you have is not an instance of the publish/subscribe pattern, its a message queue. Its easy enough to create your own message queue using a Queue{EventHandler}, where you dequeue events as you invoke them.
So instead of hooking on to an event handler, your "one-shot" events should expose a method allowing clients to add an function to the message queue.
Does it work? If so, then I say go for it. For a one-shot event that looks to be quite elegant.
What I like...
If s is garbage collected, so will the event handler.
The detaching code is right next to the attaching code, making it easy to see what you are are doing.
You might be able to generalize it, but I'm not entierly sure how to because I can't seem to get a pointer to a event.
Personally, I just create a specialized extension method for whatever type has the event I'm dealing with.
Here's a basic version of something I am using right now:
namespace MyLibrary
{
public static class FrameworkElementExtensions
{
public static void HandleWhenLoaded(this FrameworkElement el, RoutedEventHandler handler)
{
RoutedEventHandler wrapperHandler = null;
wrapperHandler = delegate
{
el.Loaded -= wrapperHandler;
handler(el, null);
};
el.Loaded += wrapperHandler;
}
}
}
The reason I think this is the best solution is because you often don't need to just handle the event one time. You also often need to check if the event has already passed... For instance, here is another version of the above extension method that uses an attached property to check if the element is already loaded, in which case it just calls the given handler right away:
namespace MyLibraryOrApplication
{
public static class FrameworkElementExtensions
{
public static void HandleWhenLoaded(this FrameworkElement el, RoutedEventHandler handler)
{
if ((bool)el.GetValue(View.IsLoadedProperty))
{
// el already loaded, call the handler now.
handler(el, null);
return;
}
// el not loaded yet. Attach a wrapper handler that can be removed upon execution.
RoutedEventHandler wrapperHandler = null;
wrapperHandler = delegate
{
el.Loaded -= wrapperHandler;
el.SetValue(View.IsLoadedProperty, true);
handler(el, null);
};
el.Loaded += wrapperHandler;
}
}
}
You probably want to work with the new async/await idioms.
Usually when I need to execute an event handler one-shot like you described, what I really need is something like:
await variableOfSomeSort.SomeMethodAsync();
//small snippet of code here
Why not do use the delegate stack built into the event?
Something like...
private void OnCheckedIn(object sender, Session e)
{
EventHandler<Session> nextInLine = null;
lock (_syncLock)
{
if (SessionCheckedIn != null)
{
nextInLine = (EventHandler<Session>)SessionCheckedIn.GetInvocationList()[0];
SessionCheckedIn -= nextInLine;
}
}
if ( nextInLine != null )
{
nextInLine(this, e);
}
}

How do I make event callbacks into my win forms thread safe?

When you subscribe to an event on an object from within a form, you are essentially handing over control of your callback method to the event source. You have no idea whether that event source will choose to trigger the event on a different thread.
The problem is that when the callback is invoked, you cannot assume that you can make update controls on your form because sometimes those controls will throw an exception if the event callback was called on a thread different than the thread the form was run on.
To simplify Simon's code a bit, you could use the built in generic Action delegate. It saves peppering your code with a bunch of delegate types you don't really need. Also, in .NET 3.5 they added a params parameter to the Invoke method so you don't have to define a temporary array.
void SomethingHappened(object sender, EventArgs ea)
{
if (InvokeRequired)
{
Invoke(new Action<object, EventArgs>(SomethingHappened), sender, ea);
return;
}
textBox1.Text = "Something happened";
}
Here are the salient points:
You can't make UI control calls from a different thread than the one they were created on (the form's thread).
Delegate invocations (ie, event hooks) are triggered on the same thread as the object that is firing the event.
So, if you have a separate "engine" thread doing some work and have some UI watching for state changes which can be reflected in the UI (such as a progress bar or whatever), you have a problem. The engine fire's an object changed event which has been hooked by the Form. But the callback delegate that the Form registered with the engine gets called on the engine's thread… not on the Form's thread. And so you can't update any controls from that callback. Doh!
BeginInvoke comes to the rescue. Just use this simple coding model in all your callback methods and you can be sure that things are going to be okay:
private delegate void EventArgsDelegate(object sender, EventArgs ea);
void SomethingHappened(object sender, EventArgs ea)
{
//
// Make sure this callback is on the correct thread
//
if (this.InvokeRequired)
{
this.Invoke(new EventArgsDelegate(SomethingHappened), new object[] { sender, ea });
return;
}
//
// Do something with the event such as update a control
//
textBox1.Text = "Something happened";
}
It's quite simple really.
Use InvokeRequired to find out if this callback happened on the correct thread.
If not, then reinvoke the callback on the correct thread with the same parameters. You can reinvoke a method by using the Invoke (blocking) or BeginInvoke (non-blocking) methods.
The next time the function is called, InvokeRequired returns false because we are now on the correct thread and everybody is happy.
This is a very compact way of addressing this problem and making your Forms safe from multi-threaded event callbacks.
I use anonymous methods a lot in this scenario:
void SomethingHappened(object sender, EventArgs ea)
{
MethodInvoker del = delegate{ textBox1.Text = "Something happened"; };
InvokeRequired ? Invoke( del ) : del();
}
I'm a bit late to this topic, but you might want to take a look at the Event-Based Asynchronous Pattern. When implemented properly, it guarantees that events are always raised from the UI thread.
Here's a brief example that only allows one concurrent invocation; supporting multiple invocations/events requires a little bit more plumbing.
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public class MainForm : Form
{
private TypeWithAsync _type;
[STAThread()]
public static void Main()
{
Application.EnableVisualStyles();
Application.Run(new MainForm());
}
public MainForm()
{
_type = new TypeWithAsync();
_type.DoSomethingCompleted += DoSomethingCompleted;
var panel = new FlowLayoutPanel() { Dock = DockStyle.Fill };
var btn = new Button() { Text = "Synchronous" };
btn.Click += SyncClick;
panel.Controls.Add(btn);
btn = new Button { Text = "Asynchronous" };
btn.Click += AsyncClick;
panel.Controls.Add(btn);
Controls.Add(panel);
}
private void SyncClick(object sender, EventArgs e)
{
int value = _type.DoSomething();
MessageBox.Show(string.Format("DoSomething() returned {0}.", value));
}
private void AsyncClick(object sender, EventArgs e)
{
_type.DoSomethingAsync();
}
private void DoSomethingCompleted(object sender, DoSomethingCompletedEventArgs e)
{
MessageBox.Show(string.Format("DoSomethingAsync() returned {0}.", e.Value));
}
}
class TypeWithAsync
{
private AsyncOperation _operation;
// synchronous version of method
public int DoSomething()
{
Thread.Sleep(5000);
return 27;
}
// async version of method
public void DoSomethingAsync()
{
if (_operation != null)
{
throw new InvalidOperationException("An async operation is already running.");
}
_operation = AsyncOperationManager.CreateOperation(null);
ThreadPool.QueueUserWorkItem(DoSomethingAsyncCore);
}
// wrapper used by async method to call sync version of method, matches WaitCallback so it
// can be queued by the thread pool
private void DoSomethingAsyncCore(object state)
{
int returnValue = DoSomething();
var e = new DoSomethingCompletedEventArgs(returnValue);
_operation.PostOperationCompleted(RaiseDoSomethingCompleted, e);
}
// wrapper used so async method can raise the event; matches SendOrPostCallback
private void RaiseDoSomethingCompleted(object args)
{
OnDoSomethingCompleted((DoSomethingCompletedEventArgs)args);
}
private void OnDoSomethingCompleted(DoSomethingCompletedEventArgs e)
{
var handler = DoSomethingCompleted;
if (handler != null) { handler(this, e); }
}
public EventHandler<DoSomethingCompletedEventArgs> DoSomethingCompleted;
}
public class DoSomethingCompletedEventArgs : EventArgs
{
private int _value;
public DoSomethingCompletedEventArgs(int value)
: base()
{
_value = value;
}
public int Value
{
get { return _value; }
}
}
}
As the lazy programmer, I have a very lazy method of doing this.
What I do is simply this.
private void DoInvoke(MethodInvoker del) {
if (InvokeRequired) {
Invoke(del);
} else {
del();
}
}
//example of how to call it
private void tUpdateLabel(ToolStripStatusLabel lbl, String val) {
DoInvoke(delegate { lbl.Text = val; });
}
You could inline the DoInvoke inside your function or hide it within separate function to do the dirty work for you.
Just keep in mind you can pass functions directly into the DoInvoke method.
private void directPass() {
DoInvoke(this.directInvoke);
}
private void directInvoke() {
textLabel.Text = "Directly passed.";
}
In many simple cases, you can use the MethodInvoker delegate and avoid the need to create your own delegate type.

Categories