I my class I have an event with arguments containing boolean field Prevent and a default function doing some stuff if Prevent == false. I want user of my class to be able to prevent default function from doing stuff by setting Prevent = true in function listening to event. But it turned out that default function is invoked first, with Prevent = true, and then the user-defined function changes the value of the field. Is there any way of changing order of function invokation? Or any other approach which can give me the same results? I've done it by defining Func field used to check if default function should do its things and user can modify the field providing own function. It works, but I don't like the fact that 2 separate functions are needed, one to do stuff when event fires and one to prevent default behaviour.
Some of the code:
public Func<int, int, bool> PreventFunc = new Func<int,int,bool>( (x,y) => {return false;});
public struct MyEventArgs
{
int x;
int y;
bool Prevent;
public MyEventArgs (int i, int j, bool prev) { /*assignments*/ }
}
public delegate void MyEventDelegate(object sender, MyEventArgs e);
public event MyEventDelegate MyEvent = DefaultBehaviourFunction;
void DefaultBehaviourFunction (object sender, MyEventArgs e)
{
if (e.Prevent == true) return;
//do stuff
}
And when invoking an event
MyEvent.Invoke(sender, new MyEventArgs(i, j, PreventFunc(i,j)));
I want it to work without the PreventFunc, like that:
MyEvent += Func;
void Func (object sender, MyEventArgs e)
{
if (e.x == 1) e.Prevent = true;
//do stuff
}
You could accomplish what you are asking for literally, by getting the invocation list from the event delegate field, reversing the order, and invoking each target individually. But that would be an abuse of the event pattern, as well as simply being unwieldy.
Instead, you should implement this the way that other classes do: have the method that raises the event be the one that checks the Prevent value, not some other handler.
For example:
private void OnMyEvent(int i, int j, bool prevent)
{
MyEventDelegate handler = MyEvent;
MyEventArgs e = new MyEventArgs(i, j, prevent);
if (handler != null)
{
handler(this, e);
}
if (e.Prevent)
{
return;
}
// Member of same class, and we already know Prevent is false,
// so just need to pass i and j.
DefaultBehaviourFunction(i, j);
}
then instead of invoking the event handlers directly with MyEvent.Invoke() you'd call the OnMyEvent() method instead.
Related
Sometimes I need to add and remove events from bunch of controls. And I always do that with one method for adding events:
private void AddEvents(){
textBox.TextChanged += TextChanged;
integerUpDown.ValueChanged += ValueChanged;
colorPicker.SelectedColorChanged += ColorChanged;
//... and so on
}
And same one for removing events:
private void RemoveEvents(){
textBox.TextChanged -= TextChanged;
integerUpDown.ValueChanged -= ValueChanged;
colorPicker.SelectedColorChanged -= ColorChanged;
//... and so on
}
I'm using different types of controls and different types of EventArgs. I'd like to compress it to one method, something like:
private void RemoveEvents(bool add){
textBox.TextChanged add ? += : -= TextChanged;
integerUpDown.ValueChanged add ? += : -= ValueChanged;
//or method approach
ManageEvent(colorPicker.SelectedColorChanged, ColorChanged, add);
//... and so on
}
But that's not possible with ? operator. Is there a way to do it?
I think this is neat.
First, define the following interface and class:
public interface IEventHolder
{
void Attach();
void Detach();
}
public class EventHolder<H> : IEventHolder
{
private Action<H> _add;
private Action<H> _remove;
private H _handler;
public EventHolder(Action<H> add, Action<H> remove, H handler)
{
_add = add;
_remove = remove;
_handler = handler;
}
public void Attach() { _add(_handler); }
public void Detach() { _remove(_handler); }
}
Now you can define this private field:
private List<IEventHolder> _eventHolders = new List<IEventHolder>();
In the Form_Load event I've written this code:
private void Form1_Load(object sender, EventArgs e)
{
_eventHolders.Add(new EventHolder<EventHandler>(h => textBox1.TextChanged += h, h => textBox1.TextChanged -= h, textBox1_TextChanged));
_eventHolders.Add(new EventHolder<EventHandler>(h => numericUpDown1.ValueChanged += h, h => numericUpDown1.ValueChanged -= h, numericUpDown1_ValueChanged));
_eventHolders.Add(new EventHolder<MouseEventHandler>(h => textBox2.MouseMove += h, h => textBox2.MouseMove -= h, textBox2_MouseMove));
_eventHolders.ForEach(eh => eh.Attach());
}
Notice that the line _eventHolders.ForEach(eh => eh.Attach()); attaches all events.
My handlers look like this:
private void textBox1_TextChanged(object sender, EventArgs e)
{ }
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
this.textBox1.Text = numericUpDown1.Value.ToString();
}
private void textBox2_MouseMove(object sender, MouseEventArgs e)
{
_eventHolders.ForEach(eh => eh.Detach());
}
The textBox2_MouseMove handler detaches all of the events in one go.
I've tested this and it works like a treat.
As you want to avoid having to specify both adding and removing a handler, there is only reflection left.
private static void ManageEvent(object target, string evnt, EventHandler handler, bool add)
{
var ei = target.GetType().GetEvent(evnt);
if(add)
{
ei.AddEventHandler(target, handler);
}else{
ei.RemoveEventHandler(target, handler);
}
}
This method finds the target event info on a given instance, and based on a condition invokes either the add or remove method. You can also make this generic, but then you would have to specify the type of the delegate. This assumes EventHandler, which is quite common.
ManageEvent(textBox, "TextChanged", TextChanged, add);
In C# 6, you can also use nameof(textBox.TextChanged) instead of "TextChanged" which makes your code easier to refactor.
Please note that reflection performs mostly slow, so consider using the approach shown in other answers if you have to call this method a lot.
This all is necessary because the events are located in another class, and you cannot thus access directly their backing field. However, if the event is located in your class, you can pass it as a reference to a similar helper method:
private static void ManageEvent<TDel>(ref TDel source, TDel value, bool add) where TDel : class
{
if(add)
{
source = (TDel)(object)Delegate.Combine((Delegate)(object)source, (Delegate)(object)value);
}else{
source = (TDel)(object)Delegate.Remove((Delegate)(object)source, (Delegate)(object)value);
}
}
This does exactly what normal event methods do, either combine or remove events.
ManageEvent(ref MyEvent, MyEventHandler, add);
The conditional operation returns a value based on the statement's result. Returning "+=" is definitely not valid, since you are basically subscribing to the event. https://msdn.microsoft.com/en-us/library/ty67wk28.aspx
However, why don't you take the simpler approach?
private void AddOrRemoveEvents(bool add)
{
if (add)
{
AddEvents();
}
else
{
RemoveEvents();
}
}
One line if statement to the rescue! There will be a little bit of repetition but none the less it is a one liner
if (add) textbox.TextChanged += TextChanged; else textbox.TextChanged -= TextChanged;
I have problem with event. For example let i have event
public event EventHandler<AxisChangedEventArgs> AxisChanged
which fires when Axis pan or zoom or something else. When it's firing i am making Console.WriteLine("Working");. How can i pass CFDBOX parameter into SomeWork anonymous method does not help because it will be imposible to unsubscribe from it. And i cannot override AxisChanged event.
public void AddEvents(CFDBOX CFDBOX) {
CFDBOX.PlotModel.Axes[0].AxisChanged += SomeWork;
}
public void RemoveEvents(CFDBOX CFDBOX) {
CFDBOX.PlotModel.Axes[0].AxisChanged -= SomeWork;
}
public EventHandler<AxisChangedEventArgs> SomeWork =
delegate(object o, AxisChangedEventArgs args) {
Console.WriteLine("Working");
}
;
Take advantage of closure lambda expressions:
private EventHandler<AxisChangedEventArgs> axisChangedEventHandler;
public void AddEvent(CFDBOX CFDBOX) {
// keep a reference of the event handler to remove it later
axisChangedEventHandler = (o, args) => {
// parameter CFDBOX bound to the event handler
Console.WriteLine("Working " + CFDBOX);
};
// register event handler
CFDBOX.PlotModel.Axes[0].AxisChanged += axisChangedEventHandler;
}
public void RemoveEvent() {
// unregister event handler
CFDBOX.PlotModel.Axes[0].AxisChanged -= axisChangedEventHandler;
}
Any parameter which must be passed with an event should be a member of your EventArgs implementation. In your scenario: AxisChangedEventArgs. Hope i get your question.
The sender of the event (in your case o) should always be the instance, which calls the event. So if your event get's fired from different classes (not instances!), you will have to check for the type of o.
I have an extension method to subscribe a PropertyChanged event of an object that implements INotifyPropertyChanged.
I would like that the event fires just once. Not more.
This is my method.
public static void OnPropertyChanged<T>(this INotifyPropertyChanged target, string propertyName, Action action)
{
if (target == null)
{
return;
}
PropertyChangedEventHandler handler = (obj, e) =>
{
if (propertyName == e.PropertyName)
{
action();
}
};
target.PropertyChanged -= handler;
target.PropertyChanged += handler;
}
But it does not work. I cannnot remove the event handler so the event fires every time I call this method.
I have try a different approach. Instead of using annonymous methods, something more traditional, like this:
public static void OnPropertyChanged<T>(this INotifyPropertyChanged target, string propertyName, Action action)
{
if (target == null)
{
return;
}
target.PropertyChanged -= target_PropertyChanged;
target.PropertyChanged += target_PropertyChanged;
}
static void target_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
//do stuff here
}
And it just works fine. The event fires just once, but I also need the Action parameter. I cannot use it with this approach.
Any workaround or different aproach to solve this issue?Is there something strange with anonymous methods inside static methods?
Thanks in advance.
That is a limitation of using anonymous methods as event handlers. They cannot be removed as you would a normal method (which is technically a delegate instance automatically create via a method group conversion) because anonymous methods get compiled into a compiler-generated container class and a new instance of the class is created each time.
In order to preserve the action parameter you could create a container class which would have the delegate for your event handler inside. The class can be declared private inside the of the other class you're working with - or made internal, maybe in a "Helpers" namespace. It would look something like this:
class DelegateContainer
{
public DelegateContainer(Action theAction, string propName)
{
TheAction = theAction;
PopertyName = propName;
}
public Action TheAction { get; private set; }
public string PropertyName { get; private set; }
public void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
{
if(PropertyName == e.PropertyName)
TheAction();
}
}
Then, create and store the reference to the container in your class. You might create a static member currentContainer and then set the handler like this:
private static DelegateContainer currentContainer;
public static void OnPropertyChanged<T>(this INotifyPropertyChanged target, string propertyName, Action action)
{
if (target == null)
{
return;
}
if(currentContainer != null)
target.PropertyChanged -= currentContainer.PropertyChangedHandler;
currentContainer = new DelegateContainer(action, propertyName);
target.PropertyChanged += currentContainer.PropertyChangedHandler;
}
You can get your first example to work if you unsubscribe from within the event handler itself.
public static void OnPropertyChanged<T>(this INotifyPropertyChanged target, string propertyName, Action action)
{
if (target == null)
{
return;
}
// Declare the handler first, in order to create
// a concrete reference that you can use from within
// the delegate
PropertyChangedEventHandler handler = null;
handler = (obj, e) =>
{
if (propertyName == e.PropertyName)
{
obj.PropertyChanged -= handler; //un-register yourself
action();
}
};
target.PropertyChanged += handler;
}
The above code serves as a "one and done" event handler. You can register an unlimited number of these, and each one will only be executed once before unregistering itself.
Keep in mind that it's possible to have one of these handlers execute multiple times, if you raise the event across multiple threads in short succession. To prevent this, you might need to create a static Dictionary(T,T) mapping object instances to "lock objects," and add some sentry code to ensure that a handler is only executed once. Those implementation specifics seem to be a bit outside the scope of your question as currently written, however.
Technically, it's not the same anonymous method you are trying to unsubscribe. .NET creates new instance of that method every time your OnPropertyChanged called. That's why unsubscription will not work.
I have two event handlers wired up to a button click in a Windows form like so:
this.BtnCreate.Click += new System.EventHandler(new RdlcCreator().FirstHandler);
this.BtnCreate.Click += new System.EventHandler(this.BtnCreate_Click);
both are being called correctly.
However is it possible within FirstHandler() to prevent BtnCreate_Click() being executed? Something like:
void FirstHandler(object sender, EventArgs e)
{
if (ConditionSatisfied)
//Prevent next handler in sequence being executed
}
I know I could just unsubscribe the event, but can this be done programmatically (from within the method)?
As far as I know there is no solution for this. That's because there is no guarantee for the order in which the event handlers are called when the event happens.
Because of that you are not supposed to rely on their order in any way.
Why don't you just replace them with one eventhandler? Something like this:
var rdlc = new RdlcCreator();
this.BtnCreate.Click += (sender, e) => {
rdlc.FirstHandler(sender, e);
if (!rdlc.HasHandledStuff) { // <-- You would need some kind of flag
this.BtnCreate_Click(sender, e);
}
};
That way you can also guarantee the order of the handlers. Alternatively, use the above implementation, but change the signature of FirstHandler to return a bool indicating the condition (as in this case it doesn't really need to have the event's signature anymore):
if (!rdlc.FirstHandler(sender, e)) {
this.BtnCreate_Click(sender, e);
}
EDIT: OR, you just pass the second handler to FirstHandler.
Change the signature of FirstHandler to this:
void FirstHandler(object sender, EventArgs e, EventHandler nextHandler) {
if (ConditionSatisfied) {
// do stuff
}
else if (nextHandler != null) {
nextHandler(sender, e);
}
}
and then:
this.BtnCreate.Click +=
(s, e) => new RdlcCreator().Firsthandler(s, e, this.BtnCreate_Click);
System.ComponentModel namespace contains a CancelEventHandler delegate which is used for this purpose. One of the arguments it provides is a CancelEventArgs instance which contains a boolean Cancel property which can be set be any of the handlers to signal that execution of the invocation list should be stopped.
However, to attach it to a plain EventHandler delegate, you will need to create your own wrapper, something like:
public static class CancellableEventChain
{
public static EventHandler CreateFrom(params CancelEventHandler[] chain)
{
return (sender, dummy) =>
{
var args = new CancelEventArgs(false);
foreach (var handler in chain)
{
handler(sender, args);
if (args.Cancel)
break;
}
};
}
}
For your example, you would use it like this:
this.BtnCreate.Click += CancellableEventChain.CreateFrom(
new RdlcCreator().FirstHandler,
this.BtnCreate_Click
/* ... */
);
Of course, you would need to capture the created chain handler in a field if you need to unsubscribe (detach) it later.
Add the following condition in this.BtnCreate_Click which is the the second event
BtnCreate_Click(object sender, EventArgs e)
{
if (!ConditionSatisfied) //Prevent next handler in sequence being executed
{
// your implementation goes here
}
}
I suggest you to create a some kind of class wrapper. So, you could store there some kind of event flag group (16bit integer, for example) and a few methods to set or unset individual bits (where each means to invoke or not particular EventHandler). You can easily store any count of the Eventhandlers or even Actions, in the class, and invoke in any order you want.
Was finding the solution to the same question, but no luck. So had to resolve myself.
A base class for Cancelable event args
public class CancelableEventArgs
{
public bool Cancelled { get; set; }
public void CancelFutherProcessing()
{
Cancelled = true;
}
}
Next defines the extension method for the EventHandler, note that Invocation List subscribers invoked in backward order (in my case UI elements subscibe the event as they added to components, so which element is rendered later has most visiblility and more priority)
public static class CommonExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void SafeInvokeWithCancel<T>(this EventHandler<T> handler, object sender, T args) where T : CancelableEventArgs
{
if (handler != null)
{
foreach (var d in handler.GetInvocationList().Reverse())
{
d.DynamicInvoke(sender, args);
if (args.Cancelled)
{
break;
}
}
}
}
And here is the usage
public class ChessboardEventArgs : CancelableEventArgs
{
public Vector2 Position { get; set; }
}
So if an UI element has some behaviour on the event, it cancells futher processing
game.OnMouseLeftButtonDown += (sender, a) =>
{
var xy = GetChessboardPositionByScreenPosition(a.XY);
if (IsInside(xy))
{
var args = new ChessboardEventArgs { Position = xy };
OnMouseDown.SafeInvokeWithCancel(this, args);
a.CancelFutherProcessing();
}
};
I'm doing a small multi-threaded app that uses asynchronous TCP sockets, but I will get to the point: I'm using a custom event to read a value from a form and the delegate used by the event returns a string when finished.
My question here is: is that correct? is it OK to return values from the events? or is there a better way to do this? (like using a simple delegate to the form to read the values)
It's often awkward to return values from events. In practice, I've found it much easier to include a writable property on a set of custom EventArgs that is passed to the event, and then checked after the event fires -- similar to Cancel property of the WinForms FormClosing event.
I don't think it's a good idea... events are basically multicast delegates, so there can be multiple handlers. Which return value will you take in that case ?
I know this is ages after the post but thought of adding comment with code to explain Dustin Campbell answer for if someone else comes across this thread. I came across this post while trying to decide what would be best practice and this is what is meant by the answer.
Create your own custom event handler class
public class myCustomeEventArgs:EventArgs
{
public bool DoOverride { get; set; }
public string Variable1 { get; private set; }
public string Variable2{ get; private set; }
public myCustomeEventArgs(string variable1 , string variable2 )
{
DoOverride = false;
Variable1 = variable1 ;
Variables = variable2 ;
}
}
So when you create your event delegate you use your created event args like this.
public delegate void myCustomeEventHandler(object sender, myCustomeEventArgs e);
And in the class raising the event you declare the event.
public event myCustomeEventHandler myCustomeEvent;
So when you trigger the event in your class the class that listens for the event you can just in the body of the event set e.DoOverride = true; as it will be declared in the class firing the event.
Fire event for example:
if(myCustomeEvent != null)
{
var eventArgs = new myCustomeEventArgs("Some Variable", "Another Varaible");
myCustomeEvent(this, eventArgs);
//Here you can now with the return of the event work with the event args
if(eventArgs.DoOverride)
{
//Do Something
}
}
The closest example I can think of is the FormClosing event in WinForms. It lets the form cancel the event by setting the eventArgs.Cancel property to true. For you to do something similar, you would define your own event args class with the return value as a property on that class. Then pass an event args object whenever you raise the event. Whoever raised the event can inspect the event args object for the return value. Others who are receiving the event can also inspect or change the event args object.
Update: I just ran across the AppDomain.AssemblyResolve event, and it appears to be an event that returns a value. It seems you just need to declare a delegate type that returns a value, and then define your event with that delegate type. I haven't tried creating my own event like this, though. One advantage to using a property on the event argument is that all subscribers to the event can see what previous subscribers have returned.
Note: only the last event returns the result.
class Program
{
static event Func<string, bool> TheEvent;
static void Main(string[] args)
{
TheEvent += new Func<string, bool>(Program_TheEvent);
TheEvent +=new Func<string,bool>(Program_TheEvent2);
TheEvent += new Func<string, bool>(Program_TheEvent3);
var r = TheEvent("s"); //r == flase (Program_TheEvent3)
}
static bool Program_TheEvent(string arg)
{
return true;
}
static bool Program_TheEvent2(string arg)
{
return true;
}
static bool Program_TheEvent3(string arg)
{
return false;
}
}
I don't know if this is best practice but i did it this way.
Func<DataRow, bool> IsDataValid;
// some other code ....
isValid = true;
if (IsDataValid != null)
{
foreach (Func<DataRow, bool> func in IsDataValid.GetInvocationList())
{
isValid &= func(Row);
}
}
If event returns a value and there are multiple handlers registered the event returns the result value of the last called handler.
Look for an example at http://blogs.msdn.com/b/deviations/archive/2008/11/27/event-handlers-returning-values.aspx
I looped over the properties of the EventArgs like this and pulled out its X and Y values.
private void navBarControl1_Click(object sender, EventArgs e)
{
int _x = 0;
int _y = 0;
Type t = e.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(t.GetProperties());
foreach (PropertyInfo prop in props)
{
if (prop.Name == "X")
{
object propValue = prop.GetValue(e, null);
_x = Convert.ToInt32(propValue);
}
if (prop.Name == "Y")
{
object propValue = prop.GetValue(e, null);
_y = Convert.ToInt32(propValue);
}
}
void method()
{
list<string> strings = new list<string>();
dostuff += stuff;
dostuff += stuff;
dostuff(this, new EventHandlerArgs(){ Parameter = strings })
foreach(string currString in strings)
{
//....
}
}
void stuff(object sender, EventHandlerArgs e)
{
list<string> strings = e.Parameter as list<string>;
if (strings != null)
{
strings.Add(MyString)
}
}