How can I stop processing of further events - c#

Similar to the KeyPress events, I want whoever is subscribed to the event to be able to set e.Handled in my EventArgs class. If they return true, I no longer want to continue firing events. Any ideas how to implement this? Right now, here is my method:
protected void OnDataReceived(SocketAsyncEventArgs e)
{
if (DataReceived != null)
{
DataReceived(this, e);
}
}
From my understanding, everybody who is subscribed to the event will receive notification, so setting e.Handled = true; will have no effect here.

Sample code for a solution using Delegate.GetInvocationList:
public class MyEventArgs : EventArgs
{
public bool Handled { get; set; }
}
public class SomeClass
{
public event EventHandler<MyEventArgs> SomeEvent;
protected virtual void OnSomeEvent(MyEventArgs e)
{
var listeners = SomeEvent.GetInvocationList();
foreach (var listener in listeners)
{
if (e.Handled) break;
((EventHandler<MyEventArgs>)listener).Invoke(this, e);
}
}
}

Related

Prevent function from being invoked from within itself [duplicate]

My application in C# has a Textbox with a txt_TextChanged event.
private void txt_TextChanged(object sender, EventArgs e)
{
//Do somthin
}
But there's one specific part that I want to change txt.Text without firing the txt_TextChanged event.
txt.Text ="somthing" //Don't fire txt_TextChanged
How can I do that?
There is no direct way to prevent the raising of events for the text property, however your event handler can use a flag to determine weather or not to perform a task. This i likely to be more efficient than attaching and detaching the event handler. This can be done by a variable within the page or even a specialized class wrapper
With a variable:
skipTextChange = true;
txt.Text = "Something";
protected void TextChangedHandler(object sender, EventArgs e) {
if(skipTextChange){ return; }
/// do some stuffl
}
With specialized event handler wrapper
var eventProxy = new ConditionalEventHandler<EventArgs>(TextBox1_TextChanged);
TextBox1.TextChanged = eventProxy.EventAction;
eventProxy.RaiseEvents = false;
TextBox1.Text = "test";
public void TextBox1_TextChanged(object sender, EventArgs e) {
// some cool stuff;
}
internal class ConditionalEventHadler<TEventArgs> where TEventArgs : EventArgs
{
private Action<object,TEventArgs> handler;
public bool RaiseEvents {get; set;}
public ConditionalEventHadler(Action<object, TEventArgs> handler)
{
this.handler = handler;
}
public void EventHanlder(object sender, TEventArgs e) {
if(!RaiseEvents) { return;}
this.handler(sender, e);
}
}
txt.TextChanged -= textBox1_TextChanged; // dettach the event handler
txt.Text = "something"; // update value
txt.TextChanged += textBox1_TextChanged; // reattach the event handler
You can extend text box and introduce there a new property that will not trigger the TextChanged event.
class SilentTextBox : TextBox
{
// if true, than the TextChanged event should not be thrown
private bool Silent { get; set; }
public string SilentText
{
set
{
try
{
Silent = true;
Text = value;
}
finally
{
Silent = false;
}
}
}
protected override void OnTextChanged(EventArgs e)
{
// raise event only if the control is in non-silent state
if (!Silent)
{
base.OnTextChanged(e);
}
}
}
try this extension method
public static class TextBoxExt
{
private static readonly FieldInfo _field;
private static readonly PropertyInfo _prop;
static TextBoxExt()
{
Type type = typeof(Control);
_field = type.GetField("text", BindingFlags.Instance | BindingFlags.NonPublic);
_prop = type.GetProperty("WindowText", BindingFlags.Instance | BindingFlags.NonPublic);
}
public static void SetText(this TextBox box, string text)
{
_field.SetValue(box, text);
_prop.SetValue(box, text, null);
}
}
you can use textbox.SetText("...") to change text and the TextChanged event will not be fired.
A quick and dirty way is to do an
ctrl.Enable = false;
ctrl.Text = "Something";
ctrl.Enable = true;
and then in the OnChange event, encapsulate the offending code with a
if (ctrl.Enabled) {
// offending code here.
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
EventHandler TextChanged_EventHandler = new EventHandler(textBox1_TextChanged);
textBox1.TextChanged -= TextChanged_EventHandler;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
MessageBox.Show("BUG");
}
}
I found a simple method, suitable for event handlers and controls that are not in the same .cs file
public static void SetTextWithoutRaiseEvent(this TextBox textBox, string content)
{
var scroll = textBox.Template.FindName("PART_ContentHost", textBox);
(scroll as ScrollViewer).Content = content;
}

Difference between custom event and SystemEvent

In my application I was using SystemEvents to add objects to an ObservableCollection (code shortened for this example)
public partial class App : Application
{
private ObservableCollection<StateChanged> _messages = new ObservableCollection<StateChanged>();
public ObservableCollection<StateChanged> messages { get { return _messages; } }
protected override void OnStartup(StartupEventArgs e)
{
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
}
private void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
{
messages.Insert(0, new StateChanged(DateTime.Now, State.Logoff));
}
}
Above code works without a problem.
Because I do not only have to handle SessionSwitch events, but also SessionEnding etc. I wrote a small class that should raise a 'unified' event for some of the SystemEvents (again shortened)
public class SystemEventArgs : EventArgs
{
public State newState { get; set; }
}
public delegate void SystemEventHandler(object sender, SystemEventArgs e);
class SystemEventCollector
{
public event SystemEventHandler SessionEvent;
protected virtual void RaiseSystemEvent(SystemEventArgs e)
{
SystemEventHandler handler = this.SessionEvent;
if (handler != null)
handler(this, e);
}
public SystemEventCollector()
{
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
}
protected void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
{
SystemEventArgs ea = new SystemEventArgs();
ea.newState = State.Unknown;
RaiseSystemEvent(ea);
}
}
When I instanciate this class in my Application and subscribe to the SessionEvent, doing the same stuff, like this
public partial class App : Application
{
private ObservableCollection<StateChanged> _messages = new ObservableCollection<StateChanged>();
public ObservableCollection<StateChanged> messages { get { return _messages; } }
private SystemEventCollector _sysEventCollector = new SystemEventCollector();
protected override void OnStartup(StartupEventArgs e)
{
_sysEventCollector.SessionEvent += OnSessionEvent;
}
private void OnSessionEvent(object sender, SystemEventArgs e)
{
messages.Insert(0, new StateChanged(DateTime.Now, e.newState));
}
}
The messages.Insert() call raises an exception
This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.
I do understand that I can not update a GUI element from another thread than the one it was created on and have worked around this problem by using the extension method mentioned in this SO answer.
My question is to why this happens? My assumptions are that events are handled on the same thread as they are raised, so why is there a difference between handling the SessionSwitch event directly and my approach of raising an event when handling the SessionSwitch event? How are the SystemEvents different from my event? Do I have the correct solution to the problem? Is there a simpler solution?
From some testing it seems that the error lies in the non-working code is the instanciation of SystemEventCollector object.
MS does all the necessary marshalling in their SessionEvents.*** handlers, this is why the first example works without problems. In the non-working code SystemEventCollector is no instanciated in the OnStartup function (which is called from the UI thread) but basically with the constructor. When marshalling from the SessionEvents is done, it goes to the wrong thread, leading to the problem.
Apart from my original solution, the problem can also be solved by instanciating the SystemEventCollector in the OnStartup function.
protected override void OnStartup(StartupEventArgs e)
{
_sysEventCollector = new SystemEventCollector();
_sysEventCollector.SessionEvent += OnSessionEvent;
}

How to prevent PreviewKeyDown be called in parent class

I have two controls.
class ControlA
{
public ControlA()
{
//some code
this.PreviewKeyDown += ControlA_PreviewKeyDown;
}
protected void ControlA_PreviewKeyDown(object sender, KeyEventArgs e)
{
// do A things
}
}
I also have a control B which inherits control A
class ControlB : ControlA
{
public ControlB()
{
//some code
this.PreviewKeyDown += ControlB_PreviewKeyDown;
}
protected void ControlB_PreviewKeyDown(object sender, KeyEventArgs e)
{
// do B things
}
}
when the PreviewKeyDown event is fired, both ControlB_ and ControlA_PreviewKeyDown are fired. But I want only ControlB_PreviewKeyDown is fired for a ControlB. Is that possible? If so, how to implement that?
Thank you so much.
Assuming you can change the code of both ControlA and ControlB here's a possible solution:
class ControlA
{
public ControlA(bool subscribe = true)
{
if (subscribe)
{
this.PreviewKeyDown += ControlA_PreviewKeyDown;
}
}
protected void ControlA_PreviewKeyDown(object sender, KeyEventArgs e)
{
// do A things
}
}
class ControlB : ControlA
{
public ControlB() : base(false)
{
//some code
this.PreviewKeyDown += ControlB_PreviewKeyDown;
}
protected void ControlB_PreviewKeyDown(object sender, KeyEventArgs e)
{
// do B things
}
}
your "problem" is due to the fact that ControlB class constructor calls also the ControlA constructor... you can create a ControlA(bool fromParent=true) which doesn't add the handler of this.PreviewKeyDown += ControlA_PreviewKeyDown;
HTH
Try setting e.Handled = true; in the ControlB handler, and in the ControlA handler, wrap the logic in an if(!e.Handled)
Or, since you have the ControlA handler as protected, you can unsubscribe from it in ControlB constructor:
this.PreviewKeyDown += ControlB_PreviewKeyDown;
In PreviewKeyDown we will check for sender type to determine from which control event fired.
Like
protected void ControlA_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (sender.GetType() == typeof(ControlA))
{
// do A things
}
}
protected void ControlB_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (sender.GetType() == typeof(ControlB))
{
// do A things
}
}

EventHandler listener

I'm in a position where I have two classes, one has an event handler for a button and I need to be able to listen to that event handler in the other class in order to make changes in the non-button class. I don't have much experience with this type of scenario so am not quite sure where to start.
Here is an exampple of this two classes (if I understood the question right).
class Form
{
Button _button1, _button2;
public Form()
{
_button1 = new Button("button1");
_button2 = new Button("button2");
_button1.Click += _button_Click;
_button2.Click += _button_Click;
}
void _button_Click(object sender, EventArgs e)
{
Button button = (Button)sender;
Console.WriteLine(button.Name);
}
public void Click1()
{
_button1.FireEvent();
}
public void Click2()
{
_button2.FireEvent();
}
}
class Button
{
public event EventHandler Click;
public string Name;
public Button(string name)
{
Name = name;
}
public void FireEvent()
{
Click(this, new EventArgs());
}
}
Usage:
Form f = new Form();
f.Click1();
f.Click2();

How to break event handler

I don't know how can I break event handler method list. For example I have follow code. What should i write in IF statement?
public event EventHandler myEvent;
...
myEvent += new EventHandler(met1);
myEvent += new EventHandler(met2);
myEvent += new EventHandler(met3);
...
public void met2(object sender, EventArgs e)
{
...
if(myCondition)
{
//there I want to break execution of all methods assiciated with myEvent event
//I want to break met2 and don't allow to execute met3
}
...
}
You can define your delegate, so your custom event handler, whith its custom EventArgs, with boolean value.
Example:
public class MyEventArg : EventArgs {
public bool Handle {get;set;}
}
myEvent += new MyEventHandler(met1);
public void met2(object sender, MyEventArgs e)
{
if(e.Handled)
return;
if(myCondition)
{
e.Handled = true;
return;
}
...
}
In this way, if we in any other event handlder before processing it, check if Handled == true, one time it's set into that state from one of them, others would skip that event processing.
Just an idea example, you have to change it to fit your code exact needs.
Look into KeyDownEventArgs, there is an Property Handled wich can be set to true.
You could do something similar:
class myClass {
public event EventHandler myEvent;
myEvent += new EventHandler(met1);
myEvent += new EventHandler(met2);
myEvent += new EventHandler(met3);
public void metN(object sender, MyCustomEventArgs e)
{
if(e.Cancel)
return;
// Do whatever you like
if(<someBooleanStatement>)
{
e.Cancel = true;
return;
}
// Do whatever you like
}
}

Categories

Resources