By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,898 Members | 1,383 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,898 IT Pros & Developers. It's quick & easy.

Event with multiple subscribers. Cancel invocation of other handlers.

P: n/a

Hi all,

If an event has multiple subscribers, is it possible to cancel the
invocation of event handlers from an event handler?

Or to be more specific:

I'm subscribing to the ColumnChanging event of a datatable, from two
seperate classes. I wish to do some data validating. Due to the nature of
the data validation being done, I seperated this code in two classes.

When the value changes, as expected, both event handlers are being invoked.
However, if the first validation rejects the data, the second handler really
shouldn't be invoked anymore. I would like to cancel the remaining handler
invocations.

Is this (easily) possible?

Thanks.

Jan 15 '06 #1
Share this Question
Share on Google+
6 Replies


P: n/a
Peter,

It's not easy, but it is possible.

What you want to do is derive your EventArgs class from CancelEventArgs.
This exposes a Cancel property which can be set to true to indicate that the
action should be cancelled.

Then, what you have to do is get the invocation list for your field
where the event is stored. You can do this by calling GetInvocationList.

Then, you would loop through that list, calling the delegate. If the
Cancel property is set to true, then you stop invocation.

Of course, this means your event handlers have to set the Cancel
property to indicate that there is a problem, or the validation failed.

Hope this helps.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Peter M." <Pe*****************@chello.nl> wrote in message
news:20**************************@news.chello.nl.. .

Hi all,

If an event has multiple subscribers, is it possible to cancel the
invocation of event handlers from an event handler?

Or to be more specific:

I'm subscribing to the ColumnChanging event of a datatable, from two
seperate classes. I wish to do some data validating. Due to the nature of
the data validation being done, I seperated this code in two classes.

When the value changes, as expected, both event handlers are being
invoked. However, if the first validation rejects the data, the second
handler really shouldn't be invoked anymore. I would like to cancel the
remaining handler invocations.

Is this (easily) possible?

Thanks.

Jan 15 '06 #2

P: n/a

Thanks for your answer. Your answer pretty much confirms what I was afraid
of, that an easy clean solution is not readily availabe.

I think I will give my design some more thought and put validation code in
one place.

"Nicholas Paldino [.NET/C# MVP]" <mv*@spam.guard.caspershouse.com> schreef
in bericht news:%2****************@TK2MSFTNGP09.phx.gbl...
Peter,

It's not easy, but it is possible.

What you want to do is derive your EventArgs class from
CancelEventArgs. This exposes a Cancel property which can be set to true
to indicate that the action should be cancelled.

Then, what you have to do is get the invocation list for your field
where the event is stored. You can do this by calling GetInvocationList.

Then, you would loop through that list, calling the delegate. If the
Cancel property is set to true, then you stop invocation.

Of course, this means your event handlers have to set the Cancel
property to indicate that there is a problem, or the validation failed.

Hope this helps.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Peter M." <Pe*****************@chello.nl> wrote in message
news:20**************************@news.chello.nl.. .

Hi all,

If an event has multiple subscribers, is it possible to cancel the
invocation of event handlers from an event handler?

Or to be more specific:

I'm subscribing to the ColumnChanging event of a datatable, from two
seperate classes. I wish to do some data validating. Due to the nature of
the data validation being done, I seperated this code in two classes.

When the value changes, as expected, both event handlers are being
invoked. However, if the first validation rejects the data, the second
handler really shouldn't be invoked anymore. I would like to cancel the
remaining handler invocations.

Is this (easily) possible?

Thanks.


Jan 15 '06 #3

P: n/a
To be fair, this adds about 2 lines to the code that fires the event - one
"foreach", and one "if"... and could probably be wrapped into a helper
function for even more re-use in about 2 minutes... to me that qualifies as
easy, *reasonably* clean, and readily available.

Marc

"Peter M." <Pe*****************@chello.nl> wrote in message
news:90**************************@news.chello.nl.. .

Thanks for your answer. Your answer pretty much confirms what I was afraid
of, that an easy clean solution is not readily availabe.

I think I will give my design some more thought and put validation code in
one place.

"Nicholas Paldino [.NET/C# MVP]" <mv*@spam.guard.caspershouse.com> schreef
in bericht news:%2****************@TK2MSFTNGP09.phx.gbl...
Peter,

It's not easy, but it is possible.

What you want to do is derive your EventArgs class from
CancelEventArgs. This exposes a Cancel property which can be set to true
to indicate that the action should be cancelled.

Then, what you have to do is get the invocation list for your field
where the event is stored. You can do this by calling GetInvocationList.

Then, you would loop through that list, calling the delegate. If the
Cancel property is set to true, then you stop invocation.

Of course, this means your event handlers have to set the Cancel
property to indicate that there is a problem, or the validation failed.

Hope this helps.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Peter M." <Pe*****************@chello.nl> wrote in message
news:20**************************@news.chello.nl.. .

Hi all,

If an event has multiple subscribers, is it possible to cancel the
invocation of event handlers from an event handler?

Or to be more specific:

I'm subscribing to the ColumnChanging event of a datatable, from two
seperate classes. I wish to do some data validating. Due to the nature
of the data validation being done, I seperated this code in two classes.

When the value changes, as expected, both event handlers are being
invoked. However, if the first validation rejects the data, the second
handler really shouldn't be invoked anymore. I would like to cancel the
remaining handler invocations.

Is this (easily) possible?

Thanks.



Jan 15 '06 #4

P: n/a
Apols - I misread the event details; since the datatable's event isn't owned
by your code, this would indeed be quite tricky. However, you could (maybe)
subscribe with a forwarding mechanism? i.e. you have one instance (of a
proxy class) subscribe to the datatable's events, which then enumerates
through it's own subscribers (exposing the original args as a param of the
new CancelEventArgs based args), stopping if/when necessary

Perhaps...

Marc

"Marc Gravell" <mg******@rm.com> wrote in message
news:OO**************@tk2msftngp13.phx.gbl...
To be fair, this adds about 2 lines to the code that fires the event - one
"foreach", and one "if"... and could probably be wrapped into a helper
function for even more re-use in about 2 minutes... to me that qualifies
as easy, *reasonably* clean, and readily available.

Marc

"Peter M." <Pe*****************@chello.nl> wrote in message
news:90**************************@news.chello.nl.. .

Thanks for your answer. Your answer pretty much confirms what I was
afraid of, that an easy clean solution is not readily availabe.

I think I will give my design some more thought and put validation code
in one place.

"Nicholas Paldino [.NET/C# MVP]" <mv*@spam.guard.caspershouse.com>
schreef in bericht news:%2****************@TK2MSFTNGP09.phx.gbl...
Peter,

It's not easy, but it is possible.

What you want to do is derive your EventArgs class from
CancelEventArgs. This exposes a Cancel property which can be set to true
to indicate that the action should be cancelled.

Then, what you have to do is get the invocation list for your field
where the event is stored. You can do this by calling
GetInvocationList.

Then, you would loop through that list, calling the delegate. If the
Cancel property is set to true, then you stop invocation.

Of course, this means your event handlers have to set the Cancel
property to indicate that there is a problem, or the validation failed.

Hope this helps.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Peter M." <Pe*****************@chello.nl> wrote in message
news:20**************************@news.chello.nl.. .

Hi all,

If an event has multiple subscribers, is it possible to cancel the
invocation of event handlers from an event handler?

Or to be more specific:

I'm subscribing to the ColumnChanging event of a datatable, from two
seperate classes. I wish to do some data validating. Due to the nature
of the data validation being done, I seperated this code in two
classes.

When the value changes, as expected, both event handlers are being
invoked. However, if the first validation rejects the data, the second
handler really shouldn't be invoked anymore. I would like to cancel the
remaining handler invocations.

Is this (easily) possible?

Thanks.




Jan 15 '06 #5

P: n/a
To show what I meant: here, EventProxy will only work with EventArgs type
args, and Handler will only match the standard event-handler signature, but
this code suffices to short-circuit the invocation of events where we don't
own the original code (i.e. we can't change it to a simple CancelEventArgs
type implementation). In the demo, note that if you press a, only "1" & "2"
are fired; if you use Ctrl, only "1" is fired, else they all do.

This might save you from refactoring? Of course, you still need to indicate
to the original args what happened...

Marc

public static void Main() {
using (Form form = new Form()) {
TextBox tb = new TextBox();
form.Controls.Add(tb);
EventProxy<KeyEventArgs> ep = new
EventProxy<KeyEventArgs>();
ep.Event += Handler1;
ep.Event += Handler2;
ep.Event += Handler3;
tb.KeyDown += ep.Handler;
form.ShowDialog();
}
}

static void Handler1(object sender,
EventProxyEventArgs<KeyEventArgs> e) {
System.Diagnostics.Debug.WriteLine("Handler1");
if (e.InnerEventArgs.Control)
e.Cancel = true;
}
static void Handler2(object sender,
EventProxyEventArgs<KeyEventArgs> e) {
System.Diagnostics.Debug.WriteLine("Handler2");
if (e.InnerEventArgs.KeyData == Keys.A)
e.Cancel = true;
}
static void Handler3(object sender,
EventProxyEventArgs<KeyEventArgs> e) {
System.Diagnostics.Debug.WriteLine("Handler3");
}
}

public class EventProxyEventArgs<T> : CancelEventArgs where T :
EventArgs {
public readonly T InnerEventArgs; // cheap for demo
public EventProxyEventArgs(T innerEventArgs) {
InnerEventArgs = innerEventArgs;
}
}
public class EventProxy<T> where T : EventArgs {
public event EventHandler<EventProxyEventArgs<T>> Event;
public void Handler(object sender, T eventArgs) {
if (Event != null) {
EventProxyEventArgs<T> args = new
EventProxyEventArgs<T>(eventArgs);
foreach(EventHandler<EventProxyEventArgs<T>> subscriber in
Event.GetInvocationList()) {
subscriber(sender, args); // using original sender;
could use "this" and pass original in args
if (args.Cancel) break;
}
}

}
}
Jan 15 '06 #6

P: n/a
Marc,

Thanks for your answer.

I 'll try your code and see if this could be of any help.

I appreciate the effort.

peter.
"Marc Gravell" <mg******@rm.com> schreef in bericht
news:eh**************@TK2MSFTNGP14.phx.gbl...
To show what I meant: here, EventProxy will only work with EventArgs type
args, and Handler will only match the standard event-handler signature,
but this code suffices to short-circuit the invocation of events where we
don't own the original code (i.e. we can't change it to a simple
CancelEventArgs type implementation). In the demo, note that if you press
a, only "1" & "2" are fired; if you use Ctrl, only "1" is fired, else they
all do.

This might save you from refactoring? Of course, you still need to
indicate to the original args what happened...

Marc

public static void Main() {
using (Form form = new Form()) {
TextBox tb = new TextBox();
form.Controls.Add(tb);
EventProxy<KeyEventArgs> ep = new
EventProxy<KeyEventArgs>();
ep.Event += Handler1;
ep.Event += Handler2;
ep.Event += Handler3;
tb.KeyDown += ep.Handler;
form.ShowDialog();
}
}

static void Handler1(object sender,
EventProxyEventArgs<KeyEventArgs> e) {
System.Diagnostics.Debug.WriteLine("Handler1");
if (e.InnerEventArgs.Control)
e.Cancel = true;
}
static void Handler2(object sender,
EventProxyEventArgs<KeyEventArgs> e) {
System.Diagnostics.Debug.WriteLine("Handler2");
if (e.InnerEventArgs.KeyData == Keys.A)
e.Cancel = true;
}
static void Handler3(object sender,
EventProxyEventArgs<KeyEventArgs> e) {
System.Diagnostics.Debug.WriteLine("Handler3");
}
}

public class EventProxyEventArgs<T> : CancelEventArgs where T :
EventArgs {
public readonly T InnerEventArgs; // cheap for demo
public EventProxyEventArgs(T innerEventArgs) {
InnerEventArgs = innerEventArgs;
}
}
public class EventProxy<T> where T : EventArgs {
public event EventHandler<EventProxyEventArgs<T>> Event;
public void Handler(object sender, T eventArgs) {
if (Event != null) {
EventProxyEventArgs<T> args = new
EventProxyEventArgs<T>(eventArgs);
foreach(EventHandler<EventProxyEventArgs<T>> subscriber in
Event.GetInvocationList()) {
subscriber(sender, args); // using original sender;
could use "this" and pass original in args
if (args.Cancel) break;
}
}

}
}

Jan 17 '06 #7

This discussion thread is closed

Replies have been disabled for this discussion.