EventHandler called once without event fired
public class Observable<T>
{
public delegate void ValueChanged(T value);
event ValueChanged Changed;
public T Value { get; private set; }
public Observable(T t)
{
Value = t;
}
/*
public void Set(T value)
{
if (Equals(value, Value))
{
return;
}
Value = value;
Changed?.Invoke(Value);
}
*/
public void Subscribe(ValueChanged action)
{
Changed += action;
}
}
I am currently seeing the issue in the user permission handling of a Xamarin mobile app I am working on
ViewModel reads local storage to get latest saved permission (mobile). It creates the Obervable<Permisson> property passing the saved value in the constructor:
var savedCamera = HistoryService.GetStatus<Permissions.Camera>()
CameraPermissionProperty = new Observable<PermissionStatus>(savedCamera); // <--
Then subscription is made
CameraPermissionProperty.Subscribe(SendPermission<Permissions.Camera>);
The SendPermission<Permissions.Camera> method is triggered once with value set in the Observable despite not having invoked the ValueChanged delegate.
I can't repoduce this in a console app.
What could be the issue, could be related to threading?
I added a number to see which method was called:
// ... Observable
public delegate void ValueChanged(T value, int number); //<--
event ValueChanged Changed;
public void Subscribe(ValueChanged action)
{
Changed += action;
Number = 18;
}
public void SubscribeWithInitialUpdate(ValueChanged action)
{
Changed += action;
Number = 10;
Changed.Invoke(Value, Number);
}
10 is returned even though I am calling the Subscribe method
I could not reproduce your error in Xamarin, so I will try to provide some suggestions.
First here is the code I tested:
public class Observable<T>
{
public delegate void ValueChanged(T v, int n);
public event ValueChanged Changed;
public T Value { get; private set; }
public int Number; //this was missing in your code example
public Observable(T t)
{
Value = t;
}
public void Set(T value)
{
if (Equals(value, Value))
{
return;
}
Value = value; //breakpoint here
Changed?.Invoke(Value, Number);
}
public void Subscribe(ValueChanged action)
{
Changed += action;
Number = 22; //breakpoint here
Console.WriteLine("setting 22");
}
public void SubscribeWithInitialUpdate(ValueChanged action)
{
Changed += action;
Number = 11; //breakpoint here
Console.WriteLine("setting 11 - is never called");
Changed?.Invoke(Value, Number);
}
}
I executed the code from an arbitrary viewmodel's c-tor:
public class SomeViewModel // : INotifyPropertyChanged
{
public SomeViewModel()
{
obs = new Observable<string>("baar");
// subscribe to event with anonymous delegate event handler
obs.Subscribe((v,n) => { //breakpoint here
Console.WriteLine("value=" + v + " number=" + n); //breakpoint here
});
obs.Set("foo"); //breakpoint here
}
}
//console output:
//setting 22
//value=foo number=22
In Xamarin Forms, you can use breakpoints and Console.WriteLine in DEBUG mode with the Android Emulator. For me this was working as expected. So I suggest setting breakpoints at the relevant places, especially the method that should not be called, but somehow is ("SubscribeWithInitialUpdate"), maybe you will catch, when it is called. In my scenario the method was never executed, as expected.
For me this has nothing to do with invoking the event. Number = 10 is set in the method SubscribeWithInitialUpdate(), which is independent from the event. Even if the event would have been invoked from some other method multiple times, the breakpoint in that method should never be reached.
It may be that your SendPermission<Permissions.Camera> method is called from somewhere else, not from the event (though the 10 would still be a mystery). So I suggest to add a breakpoint in there aswell. Also to be sure, don't add a method than can be called as a parameter, try adding an anonymous lambda delegate (at least for debugging), so you can be sure, no other caller exists.
So my last suggestion is to try my code in a new empty Xamarin project and compare that to your project.
I am assuming you don't want to do MVVM here and use custom listeners? Otherwise I would suggest to simply implement INotifyPropertyChanged. Examples:
Link1
Link2
Link3
I hope some of this helps.
If you are using multiple threads, I assume you know what you are doing, otherwise I don't know why or how something would ever call any arbitrary method. You could check it's thread.ManagedThreadId Link
You might think about of the loading of page.
It could be launched on page load
Related
We have a click Event that inside calls a previously set Action session variable. The problem is that the changes done in the click event shows fine in the page but the changes done inside the Action method called in the invoke doesn't get shown in the page...
Debugging it seems like the Invoked method is in another context/viewstate for the page controls.
Simplified code example:
public static Action OKFunction {
get => (Action) HttpContext.Current.Session["OKFunction"];
set => HttpContext.Current.Session["OKFunction"] = value;
}
protected void FunctionPrepareCall() {
//in the long version we prepare a javascript dialog with _doPostback and set the desired target function depending on various conditions, here we show only the problematic part, setting the target function
OKFunction = DialogDeleteItemAcepted;
}
protected void ConfirmationDialogOk_Click(object sender, EventArgs e) {
lbMsg.Text = "TestConfirmDialog"; //this value is what it is shown after the page refreshes
OKFunction ? .Invoke(); //calling the target function if its assigned
string currentMsgValue = lbMsg.Text; //right here in debug the value of lbMsg.Text is the one we assigned in this method "TestConfirmDialog";
}
public void DialogDeleteItemAcepted() {
//right here in debug the value of lbMsg.Text appears empty, like it would be in another thread context/viewstate
lbMsg.Text = "TestDialogDeleteItemAcepted"; //in the real case the message text would depend on the result of the delete item operation for example
//right here in debug the value of lbMsg.Text is the one we assigned "TestDialogDeleteItemAcepted";
}
I've created a console application that demonstrates a similar issue:
using System;
namespace PlayAreaCSCon
{
internal class Program
{
public static void Main(string[] args)
{
var s = new Session();
var c1 = new Page(1, s);
c1.SetAction();
c1 = null;
var c2 = new Page(2, s);
c2.InvokeAction();
Console.ReadLine();
}
}
public class Session
{
public object Thingy;
}
public class Page
{
int _id;
Session _session;
public Page(int id, Session session)
{
_id = id;
_session = session;
}
public Action OKFunction
{
get { return (Action)_session.Thingy; }
set { _session.Thingy = value; }
}
public void SetAction()
{
OKFunction = DelegatedMethod;
}
public void DelegatedMethod()
{
Console.WriteLine($"Delegated method called on page {_id}");
}
public void InvokeAction()
{
OKFunction.Invoke();
}
}
}
Run this and it prints "Delegated method called on page 1", even though, of course, we accessed it through page "2".
So, if we change the getter of OKFunction to:
public Action OKFunction
{
get { return (Action)Delegate.CreateDelegate(typeof(Action), this,
((Action)_session.Thingy).Method); }
set { _session.Thingy = value; }
}
And now we get the output as "Delegated method called on page 2". You should be able to apply a similar transformation in your OKFunction getter to return a new Action that targets the current page. OKFunction has to become an instance method (non-static) so that it can access the this member.
This will be broken if whatever was passed to the setter of OKFunction wasn't a delegate to an instance method or was bound to an instance of some other class. You may wish to apply further validation within the setter and throw an ArgumentException of some kind if what's being set won't work.
Let's suppose I have an observable collection and two clients that want to:
change it,
observe it and react on state change.
Now, if Client1 changes collection state (for example: adds new item), the collection will fire 'CollectionChanged' event. Since both clients are registered for this event notifications, Client1's handling method will be executed.
In order to avoid self-callback on Client1, I unsubscribe from an event, do my action and subscribe again. This is painful - I must remember about suspending Client1's subscription every time Client1 touches the collection and it just seems like a bad smell. Is there a better way (design pattern, external library) that would help me in callbacks management?
Although in my example I mentioned ObservableCollection and CollectionChanged event, I believe my question is more generic and comes down to: "how to exclude an entity that caused event trigger from event callback".
Thanks in advance!
Problem keeps reoccuring in my solution, bumping the question in a hope someone might help out.
I ran into your problem some times ago I didn't find a proper solution except for this one.
The idea is that when you change the collection you also pass an instance of the object changing it.
Then when the Collection fires the event, it also passes the reference.
So all observers may know which instance did the change, and check for equality.
Here is a basic example of this implementation:
class Program
{
private static MyCollection Collection;
private static MyCollectionModifier Modif1;
private static MyCollectionModifier Modif2;
static void Main(string[] args)
{
Collection = new MyCollection();
Modif1 = new MyCollectionModifier("Modifier 1", Collection);
Modif2 = new MyCollectionModifier("Modifier 2", Collection);
Modif1.AddItem("Test1");
Modif2.AddItem("Test2");
Console.ReadKey();
}
}
public class MyCollectionItemAddedEventArgs:EventArgs
{
public Object ChangeSource { get; set;}
public int newIndex {get;set;}
}
public delegate void MyCollectionItemAddedEventHandler(object sender, MyCollectionItemAddedEventArgs e);
public class MyCollection
{
private List<String> _myList;
public String this[int Index]
{
get { return _myList[Index]; }
}
public event MyCollectionItemAddedEventHandler ItemAdded;
public MyCollection()
{
_myList = new List<string>();
}
protected virtual void OnMyCollectionItemAdded(MyCollectionItemAddedEventArgs e)
{
if (ItemAdded != null)
ItemAdded(this, e);
}
public void AddItem(String Item, object ChangeSource = null)
{
_myList.Add(Item);
var e = new MyCollectionItemAddedEventArgs();
e.ChangeSource = ChangeSource;
e.newIndex = _myList.Count;
OnMyCollectionItemAdded(e);
}
}
public class MyCollectionModifier
{
private MyCollection _collection;
public string Name { get; set; }
public MyCollectionModifier(string Name, MyCollection Collection)
{
this.Name = Name;
_collection = Collection;
_collection.ItemAdded += Collection_ItemAdded;
}
public void AddItem(string Item)
{
_collection.AddItem(Item, this);
}
void Collection_ItemAdded(object sender, MyCollectionItemAddedEventArgs e)
{
if (e != null)
{
if (this.Equals(e.ChangeSource))
{
Console.WriteLine("{0} : I changed the collection", Name);
}
else
{
Console.WriteLine("{0} : Somebody else changed the collection", Name);
}
}
}
}
I've encountered this problem before as well.
Best solution I could come up with is to create extension methods that take the handler of the caller and then automate the unsubscribe/subscribe around the called method, that way you don't have to remember to do it each time and it does not end up cluttering your code either
public static void Add<T>(this ObservableCollection<T> self, T itemToAdd, NotifyCollectionChangedEventHandler handler)
{
self.CollectionChanged -= handler;
self.Add(itemToAdd);
self.CollectionChanged += handler;
}
It does take some effort to create the extensions initially but at least you won't forget to resubscribe. Only real extra code is then around invoking the method
public class ObserverClass
{
public ObserverClass()
{
ObservableIntegers.CollectionChanged += ObservableIntegersOnCollectionChanged;
//Add item to collection while preventing self-handling the callback
ObservableIntegers.Add(1, ObservableIntegersOnCollectionChanged);
}
private void ObservableIntegersOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
{
// Handle collection change
}
public ObservableCollection<int> ObservableIntegers { get; set; }
}
To simply illustrate my dilemma, let say that I have the following code:
class A
{
// May be set by a code or by an user.
public string Property
{
set { PropertyChanged(this, EventArgs.Empty); }
}
public EventHandler PropertyChanged;
}
class B
{
private A _a;
public B(A a)
{
_a = a;
_a.PropertyChanged += Handler;
}
void Handler(object s, EventArgs e)
{
// Who changed the Property?
}
public void MakeProblem()
{
_a.Property = "make a problem";
}
}
In order to perform its duty, class B have to react on A's PropertyChanged event but also is capable of alternating that property by itself in certain circumstances. Unfortunately, also other objects can interact with the Property.
I need a solution for a sequential flow. Maybe I could just use a variable in order to disable an action:
bool _dontDoThis;
void Handler(object s, EventArgs e)
{
if (_dontDoThis)
return;
// Do this!
}
public void MakeProblem()
{
_dontDoThis = true;
_a.Property = "make a problem";
_dontDoThis = false;
}
Are there a better approaches?
Additional considerations
We are unable to change A.
A is sealed.
There are also other parties connected to the PropertyChanged event and I don't know who their are. But when I update the Property from B, they shouldn't be also notified. But I'm unable to disconnect them from the event because I don't know them.
What if also more threads can interact with the Property in the mean time?
The more bullets solved, the better.
Original problem
My original problem is a TextBox (WPF) that I want to complement depending on its content and focus. So I need to react on TextChanged event and I also need to omit that event if its origin is derived from my complements. In some cases, other listeners of a TextChanged event shouldn't be notified. Some strings in certain state and style are invisible to others.
If it is so important not to handle events you initiated, maybe you should change the way you set Property to include the initiator of the change?
public class MyEventArgs : EventArgs
{
public object Changer;
}
public void SetProperty(string p_newValue, object p_changer)
{
MyEventArgs eventArgs = new MyEventArgs { Changer = p_changer };
PropertyChanged(this, eventArgs);
}
And then in your handler - simply check your are not the initiator.
I find all these changes in registration and members very problematic in terms on multi threading and extensibility.
Well essentially you are trying to break the event delegation mechanism and any "solution" to that is going to be brittle since updates to the BCL might break your code. You could set the backing field using reflection. This of course would require that you do have permissions to do this and seeing the generic framing of the question it might not always be that you have the needed permissions
public void MakeProblem()
{
if (_backingField == null) {
_backingField = = _a.GetType().GetField(fieldname)
}
_backingField.SetValue(_a,"make a problem");
}
but as I started out, you are trying to break the event delegation mechanism. The idea is that the receivers of the event are independent. Disabling might lead to so very hard to find bugs because looking at any given piece of code it looks correct but only when you realize that some devious developer has hack the delegation mechanism do you realize why the information that is shown on screen seems to be a cached version of the actual value. The debugger shows the expected value of the property but because the event was hidden the handler responsible for updating the display was never fired and hence an old version is displayed (or the log shows incorrect information so when you are trying to recreate a problem a user has reported based on the content of the log you will not be able to because the information in the log is incorrect because it was based on no one hacking the event delegation mechanism
To my opinion your solution is possible, though I would have created a nested IDisposable class inside B that does the same thing with 'using', or put the '_dontDoThis = false' inside a 'finally' clause.
class A
{
// May be set by a code or by an user.
public string Property
{
set { if (!_dontDoThis) PropertyChanged(this, EventArgs.Empty); }
}
public EventHandler PropertyChanged;
bool _dontDoThis;
}
class B
{
private class ACallWrapper : IDisposable
{
private B _parent;
public ACallWrapper(B parent)
{
_parent = parent;
_parent._a._dontDoThis = true;
}
public void Dispose()
{
_parent._a._dontDoThis = false;
}
}
private A _a;
public B(A a)
{
_a = a;
_a.PropertyChanged += Handler;
}
void Handler(object s, EventArgs e)
{
// Who changed the Property?
}
public void MakeProblem()
{
using (new ACallWrapper(this))
_a.Property = "make a problem";
}
}
On the other hand, I would've used the 'internal' modifier for these things if those two classes are inside the same assembly.
internal bool _dontDoThis;
That way, you keep a better OOP design.
Moreover, if both classes are on the same assembly, I would've written the following code inside A:
// May be set by a code or by an user.
public string Property
{
set
{
internalSetProperty(value);
PropertyChanged(this, EventArgs.Empty);
}
}
internal internalSetProperty(string value)
{
// Code of set.
}
In this case, B could access internalSetProperty without triggering to PropertyChanged event.
Thread Sync:
NOTE: The next section applies to WinForms - I don't know if it applies to WPF as well.
For thread synchronizations, because we're referring to a control. you could use the GUI thread mechanism for synchronization:
class A : Control
{
public string Property
{
set
{
if (this.InvokeRequired)
{
this.Invoke((Action<string>)setProperty, value);
reutrn;
}
setProperty(value);
}
}
private void setProperty string()
{
PropertyChanged(this, EventArgs.Empty);
}
}
Great question.
As a general case, you can not mess around with event handlers of sealed classes. Normally you could override A's hypothetical OnPropertyChanged and based on some flag either raise the event or not. Alternatively you could provide a setter method that does not raise event, as suggested by #Vadim. However, if A is sealed your best option is to add flag to a lister, just as you did. That will enable you to recognize PropertyChanged event raised by B, but you won't be able to suppress the event for other listeners.
Now, since you provided context... There is a way of doing exactly this in WPF. All that needs to be done is B's handler for TextBox.TextChanged needs to set e.Handled = _dontDoThis. That will supress notifications for all other listeners, provided B's one was added as the first one. How to make sure this happens? Reflection!
UIElement exposes only AddHandler and RemoveHandler methods, there is no InsertHandler that would allow to manually specifiy the priority for the handler. However, a quick peek into .NET source code (either download the whole thing or query what you need) reveals that AddHandler forwards arguments to an interal method EventHandlersStore.AddRoutedEventHandler, which does this:
// Create a new RoutedEventHandler
RoutedEventHandlerInfo routedEventHandlerInfo =
new RoutedEventHandlerInfo(handler, handledEventsToo);
// Get the entry corresponding to the given RoutedEvent
FrugalObjectList<RoutedEventHandlerInfo> handlers = (FrugalObjectList<RoutedEventHandlerInfo>)this[routedEvent];
if (handlers == null)
{
_entries[routedEvent.GlobalIndex] = handlers = new FrugalObjectList<RoutedEventHandlerInfo>(1);
}
// Add the RoutedEventHandlerInfo to the list
handlers.Add(routedEventHandlerInfo);
All this stuff is internal, but can be recreated using reflection:
public static class UIElementExtensions
{
public static void InsertEventHandler(this UIElement element, int index, RoutedEvent routedEvent, Delegate handler)
{
// get EventHandlerStore
var prop = typeof(UIElement).GetProperty("EventHandlersStore", BindingFlags.NonPublic | BindingFlags.Instance);
var eventHandlerStoreType = prop.PropertyType;
var eventHandlerStore = prop.GetValue(element, new object[0]);
// get indexing operator
PropertyInfo indexingProperty = eventHandlerStoreType.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance)
.Single(x => x.Name == "Item" && x.GetIndexParameters().Length == 1 && x.GetIndexParameters()[0].ParameterType == typeof(RoutedEvent));
object handlers = indexingProperty.GetValue(eventHandlerStore, new object[] { routedEvent });
if (handlers == null)
{
// just add the handler as there are none at the moment so it is going to be the first one
if (index != 0)
{
throw new ArgumentOutOfRangeException("index");
}
element.AddHandler(routedEvent, handler);
}
else
{
// create routed event handler info
var constructor = typeof(RoutedEventHandlerInfo).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).Single();
var handlerInfo = constructor.Invoke(new object[] { handler, false });
var insertMethod = handlers.GetType().GetMethod("Insert");
insertMethod.Invoke(handlers, new object[] { index, handlerInfo });
}
}
}
Now calling InsertEventHandler(0, textBox, TextBox.TextChangedEvent, new TextChangedEventHandler(textBox_TextChanged)) will make sure your handler will be the first one on the list, enabling you to suppress notifications for other listeners!
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var textBox = new TextBox();
textBox.TextChanged += (o, e) => Console.WriteLine("External handler");
var b = new B(textBox);
textBox.Text = "foo";
b.MakeProblem();
}
}
class B
{
private TextBox _a;
bool _dontDoThis;
public B(TextBox a)
{
_a = a;
a.InsertEventHandler(0, TextBox.TextChangedEvent, new TextChangedEventHandler(Handler));
}
void Handler(object sender, TextChangedEventArgs e)
{
Console.WriteLine("B.Handler");
e.Handled = _dontDoThis;
if (_dontDoThis)
{
e.Handled = true;
return;
}
// do this!
}
public void MakeProblem()
{
try
{
_dontDoThis = true;
_a.Text = "make a problem";
}
finally
{
_dontDoThis = false;
}
}
}
Output:
B.Handler
External handler
B.Handler
I found one solution with regard to third parties, that are connected to the property and we don't want to nofify them when that property changed.
There are though the requirements:
We are capable of override the A.
The A has a virtual method that is invoked when property changed and allows to suspend the event to be raised.
The event is raised immediately when property is being changed.
The solution is to replace the A by MyA, as follows:
class A
{
// May be set by a code or by an user.
public string Property
{
set { OnPropertyChanged(EventArgs.Empty); }
}
// This is required
protected virtual void OnPropertyChanged(EventArgs e)
{
PropertyChanged(this, e);
}
public EventHandler PropertyChanged;
}
// Inject MyA instead of A
class MyA : A
{
private bool _dontDoThis;
public string MyProperty
{
set
{
try
{
_dontDoThis = true;
Property = value;
}
finally
{
_dontDoThis = false;
}
}
}
protected override void OnPropertyChanged(EventArgs e)
{
// Also third parties will be not notified
if (_dontDoThis)
return;
base.OnPropertyChanged(e);
}
}
class B
{
private MyA _a;
public B(MyA a)
{
_a = a;
_a.PropertyChanged += Handler;
}
void Handler(object s, EventArgs e)
{
// Now we know, that the event is not raised by us.
}
public void MakeProblem()
{
_a.MyProperty = "no problem";
}
}
Unfortunately we still use back bool field and we assume a single thread. To rid of the first, we could use a refactored solution suggest by EZSlaver (here). First, create a disposable wrapper:
class Scope
{
public bool IsLocked { get; set; }
public static implicit operator bool(Scope scope)
{
return scope.IsLocked;
}
}
class ScopeGuard : IDisposable
{
private Scope _scope;
public ScopeGuard(Scope scope)
{
_scope = scope;
_scope.IsLocked = true;
}
public void Dispose()
{
_scope.IsLocked = false;
}
}
Then the MyProperty might be refactored to:
private readonly Scope _dontDoThisScope = new Scope();
public string MyProperty
{
set
{
using (new ScopeGuard (_dontDoThisScope))
Property = value;
}
}
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)
}
}