I need to be able to trigger a event whenever an object is added to a Queue<Delegate>.
I created a new class that extends Queue:
public delegate void ChangedEventHandler(object sender, EventArgs e);
public class QueueWithChange<Delegate> : Queue<Delegate>
{
public event ChangedEventHandler Changed;
protected virtual void OnChanged(EventArgs e) {
if (Changed != null)
{
Changed(this, e);
}
}
}
And then attached the event from another class, like such:
QueueWithChange<TimerDelegate> eventQueue = new QueueWithChange<TimerDelegate>();
//
eventQueue.Changed += new ChangedEventHandler(delegate(object s, EventArgs ex) {
//This event is not being triggered, so this code is unreachable atm...and that is my problem
if (eventQueue.Count > 0)
{
eventQueue.Dequeue().Invoke(new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(5) });
actionTimer.Stop();
}
});
But whenever I enqueue an object (eventQueue.Enqueue(something)), the attached event is not being fired.
What am I missing here?
If you mean the non-generic Queue class, then you can just override Enqueue:
public override void Enqueue(object obj)
{
base.Enqueue(obj);
OnChanged(EventArgs.Empty);
}
However, if you mean the generic Queue<T> class, then note that there is no suitable virtual method to override. You might do better to encapsulate the queue with your own class:
(** important edit: removed base-class!!! **)
class Foo<T>
{
private readonly Queue<T> queue = new Queue<T>();
public event EventHandler Changed;
protected virtual void OnChanged()
{
if (Changed != null) Changed(this, EventArgs.Empty);
}
public virtual void Enqueue(T item)
{
queue.Enqueue(item);
OnChanged();
}
public int Count { get { return queue.Count; } }
public virtual T Dequeue()
{
T item = queue.Dequeue();
OnChanged();
return item;
}
}
However, looking at your code, it seems possible that you are using multiple threads here. If that is the case, consider a threaded queue instead.
I just did write up on what I call a TriggeredQueue. It's inspired the answer by Marc Gravell.
You can find my post here: http://joesauve.com/triggeredqueuet
And the Gist here: http://gist.github.com/jsauve/b2e8496172fdabd370c4
It has four events:
WillEnqueue
WillDequeue
DidEnqueue
DidDequeue
You can hook into any of these like so:
YourQueue.WillEnqueue += (sender, e) => {
// kick off some process
};
YourQueue.DidEnqueue += (sender, e) => {
// kick off some process
// e.Item provides access to the enqueued item, if you like
};
YourQueue.WillDequeue += (sender, e) => {
// kick off some process
};
YourQueue.DidDequeue += (sender, e) => {
// kick off some process
// e.Item provides access to the dequeued item, if you like
};
One neat trick is that you can use the DidDequeue method to kick off some process to ensure that the queue is full by making a web request or loading some data from a filesystem, etc. I use this class in Xamarin mobile apps to ensure that data and images are pre-cached in order to provide a smooth user experience, instead of loading images AFTER they scroll onto the screen (like you might see in Facebook and countless other apps).
try
public new void Enqueue(Delegate d)
{
base.Enqueue(d);
OnChanged(EventArgs.Empty);
}
You have to override Enqueue, to call OnChanged.
Related
In our WPF application, we have classes that need to "raise" a notification that something has happened, and other classes that operate as listeners to that notification and have to execute some code as a response upon getting that notification. This is the common pattern of Publish/Subscribe.
Now, I will show you how it is done in our project. I think we use a bad practice of that pattern, and this causes our UI to freeze and not be responsive as expected.
The event args class:
public class IsDisconnectedAction : EventArgs
{
public override string ToString()
{
return GetType() + " Key: ";
}
public ElementType ElementKey { get; set; }
public static ActionTemplate<IsDisconnectedAction> MY_Action = new ActionTemplate<IsDisconnectedAction>();
}
Raising the Notification
IsDisconnectedAction.MY_Action.Raise(new IsDisconnectedAction() { ElementKey = _elementKey });
The implementation of the Raise method
public void Raise(T info)
{
if (_event == null) return;
InvokeIfNecessary.Invoke(() =>
{
_event (null, info);
});
}
private event EventHandler<T> _event;
public event EventHandler<T> Event
{
add
{
lock (_lock)
{
_event += value;
}
}
remove
{
lock (_lock)
{
_event -= value;
}
}
}
private readonly object _lock = new object();
The Invoke method of InvokeIfNecessary
public static void Invoke(Action action)
{
if (Application.Current == null)
{
action();
return;
}
if (Application.Current.Dispatcher.CheckAccess())
action();
else
{
Application.Current.Dispatcher.Invoke(action, DispatcherPriority.Send);
}
}
NOTE this code is executed on the UI thread, and I think it's not the correct approach.
Then, the listener:
It can be a class in the UI that indeed need to update something in the UI:
IsDisconnectedAction.MY_Action.Event += OnElementDisconnected;
private void OnElementDisconnected(object sender, IsDisconnectedAction e)
{
if (e == null) return;
_textBlock.Text = "Disconnected";
}
It can be a class that listens to the events in the same manner but does NOT even need to update anything in the UI (Here I think that raising the event and listening to it, can all be done outside of the UI thread).
Can you please suggest what is the best practice to achieve what I want?
Sometimes these events are raised so many times per second and all of that happens in the UI thread, and I think it might harm the responsiveness of the UI. Thank!
I need the following logic implemented:
a thread to which you can subscribe/unsubscribe methods at runtime.
It's fine for all these methods to have an header such as (Object sender, EventArgs e) and to return void.
These methods scope must be the scope of the class where they are defined lexically.
There's no guarantee about the order of execution
I've come up with the following implementation, which seems to do exactly what I need: basically I start an internal thread which triggers an event each x milliseconds. You can subscribe/unsubscribe delegates to this event through appropriate methods.
Before sticking to it I'd like to know if there may be subtle issues following this approach.
public class Orchestrator
{
private Thread _mainThread;
private event MethodDelegate _mainEvent;
public delegate void MethodDelegate (Object sender, EventArgs e);
private bool _stop = false;
private short _ms = 100;
public short PollingInterval { get { return _ms; }
set
{
_ms = value;
}
}
public Orchestrator()
{
_mainThread = new Thread(new ThreadStart(_execute));
}
public void Start()
{
_stop = false;
_mainThread.Start();
}
public void Stop()
{
_stop = true;
}
public void Clear()
{
_mainEvent = null;
}
public void Push(MethodDelegate method)
{
_mainEvent += method;
}
public void Pop(MethodDelegate method)
{
_mainEvent -= method;
}
private void _execute()
{
while(!_stop)
{
if (_mainEvent != null)
try
{
_mainEvent(this, new EventArgs());
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Thread.Sleep(_ms);
}
}
}
That's basically fine. You need to make _stop volatile. In C# the event accessor methods are thread-safe so that works fine.
The exception handling is very questionable. Do you really want to spam errors to the console? Define an event OnError and report errors to the consumer of your class.
You could use a timer or await Task.Delay to save a thread. This would make sense if there are a lot of such class instances at the same time. If there is just one this is likely not worth the effort.
You have a race condition which could cause a NullReferenceException, in:
while(!_stop)
{
if (_mainEvent != null)
try
{
_mainEvent(this, new EventArgs());
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Thread.Sleep(_ms);
}
Some other thread could unsubscribe from the event or call Clear() inbetween if (_mainEvent != null) and the call of _mainEvent.
To avoid this, you should copy _mainEvent into a local variable and check that against null, and use that instead:
var mainEvent = _mainEvent;
if (mainEvent != null)
try
{
mainEvent(this, new EventArgs());
In any case, I think you should be using a Timer for this rather than rolling-your-own.
I have a repository that uses components that report events.
I want to show the reported events in the front end.
This is the repository:
public interface IXmlRepository
{
//irrelevant stuff removed
event EventHandler TraceEventHandler;
}
public class XmlPanelRepository : IXmlRepository
{
public XmlPanelRepository()
{
public event EventHandler TraceEventHandler;
var panelCom = new PanelCom(); // this is a COM object that connects to a device
// when something happens in the COM object it reports it.
panelCom.Trace += panelCom_Trace;
// I want to bubble the trace events up to my UI.
TraceEventHandler += TraceEventHandler_Tracing;
}
private void TraceEventHandler_Tracing(object sender, EventArgs e)
{
// what do I do here?
}
void panelCom_Trace(string message)
{
if (TraceEventHandler!= null) TraceEventHandler.Invoke(this, new EventArgs());
}
}
My UI uses a Service to interface with the repository. The service is defined as:
public interface IXmlConfigurationService
{
//irrelevant stuff removed
event EventHandler TraceEventHandler;
}
public class XmlConfigurationService : IXmlConfigurationService
{
public event EventHandler TraceEventHandler;
public XmlConfigurationService(IXmlRepository configurationRepository)
{
_configurationRepository.TraceEventHandler += ConfigurationRepository_TraceEventHandler;
}
void ConfigurationRepository_TraceEventHandler(object sender, EventArgs e)
{
// this never gets hit.
if (TraceEventHandler != null) TraceEventHandler.Invoke(sender, e);
}
}
If I can get this working, I presume I can follow the same steps to get the UI displaying event reports.
How can I get the Service to report the events that are occurring in the repository?
If I understand correctly, you would need to fulfil your event. This is akin to the Observable fulfilling all listening observers in the Observer Pattern. But for events written like this:
public XmlPanelRepository()
{
public event EventHandler TraceEventHandler;
var panelCom = new PanelCom(); // this is a COM object that connects to a device
// when something happens in the COM object it reports it.
panelCom.Trace += panelCom_Trace;
// I want to bubble the trace events up to my UI.
TraceEventHandler += TraceEventHandler_Tracing;
}
private void TraceEventHandler_Tracing(object sender, EventArgs e)
{
if (TraceEventHandler != null)
{
TraceEventHandler(this, e);
}
}
However, perhaps you should name the event something other than TraceEventHandler because you are now exposing an event (which usually is expressed in the past tense).
It is also worth noting that you can potentially change the event args as you bubble up (if you want to). EventHandler(TEventArgs) can help with this.
You're forgetting to use delegates...
Try something like this:
public interface IXmlRepository
{
//irrelevant stuff removed
event EventHandler TraceEventHandler;
}
public class XmlPanelRepository : IXmlRepository
{
public delegate void EventHandler(string parameter1, string parameter2);
public event EventHandler TraceEventHandler;
public XmlPanelRepository()
{
var panelCom = new PanelCom(); // this is a COM object that connects to a device
// when something happens in the COM object it reports it.
panelCom.Trace += panelCom_Trace;
}
void panelCom_Trace(string message)
{
if (EventHandler != null)
EventHandler("Event was hit, here's the message:", message);
}
}
public interface IXmlConfigurationService
{
//irrelevant stuff removed
}
public class XmlConfigurationService : IXmlConfigurationService
{
public XmlConfigurationService(IXmlRepository configurationRepository)
{
_configurationRepository.TraceEventHandler += ConfigurationRepository_EventHandler;
}
void ConfigurationRepository_EventHandler(string parameter1, string parameter2);)
{
// Do something with your parameters.
Response.Write(parameter1 + parameter2);
}
}
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);
}
}
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.