Why does my event property code cause a stack overflow exception? - c#

I'm making a custom button (Winforms Control Library) and have the code below so that all mouseenter will be added to all controls in my button. When I run it, it causes a stack overflow exception. I have the same code with Click instead of MouseEnter and it works fine. Here is the code:
public new event EventHandler MouseEnter {
add
{
this.MouseEnter += value;
foreach (Control i in Controls)
{
i.MouseEnter += value;
}
}
remove
{
this.MouseEnter -= value;
foreach (Control i in Controls)
{
i.MouseEnter -= value;
}
}
}
here is the click code:
public new event EventHandler Click {
add {
this.Click += value;
foreach (Control i in Controls) {
i.Click += value;
}
}
remove {
this.Click -= value;
foreach (Control i in Controls) {
i.Click -= value;
}
}
}

+= is shorthand for "invoke the adder for this event." You are calling += from your adder. Thus you have unbound recursion, leading to the stack overflow.
Looking at your code, it appears that you are defining the adder yourself in order to add and remove the handler not only from the control, but from all its children as well. This strikes me as a pretty bad idea: subscribers to a given event have the reasonable expectation that they will only be notified when the actual event is fired, and not whenever the event is fired by any number of publishers about which they know nothing.
If you want to create helper methods that do this, that would probably make more sense, since now consumers invoking the methods know exactly what they're getting into. As well, that would get rid of your recursion bug to boot.
Finally, this functionality is probably unnecessary: many events will bubble up from children to parents anyway.

I think you wanted something like this (not sure if its right for the private member):
private EventHandler mouseEnter;
public new event EventHandler MouseEnter {
add
{
this.mouseEnter += value;
foreach (Control i in Controls)
{
i.mouseEnter += value;
}
}
remove
{
this.mouseEnter -= value;
foreach (Control i in Controls)
{
i.mouseEnter -= value;
}
}
}
You have this.MouseEnter calling itself in recursion.

I ended up replaceing this.Click with base.Click.
public new event EventHandler Click {
add {
base.Click += value;
foreach (Control i in Controls) {
i.Click += value;
}
}
remove {
base.Click -= value;
foreach (Control i in Controls) {
i.Click -= value;
}
}
}

Related

How to Convert RoutedEventHandler to EventHandler

I got this situation where I need to create a wrapper around a WPF window that exposes basic features, such as exposing Loaded and Closed events. (There are other wrapper implementations for other UI platforms)
// This works.
public event EventHandler? Closed
{
add => Ref.Closed += value;
remove => Ref.Closed -= value;
}
// This doesn't work.
public event EventHandler? Loaded
{
add => Ref.Loaded += value;
remove => Ref.Loaded -= value;
}
The problem here is that Loaded is a RoutedEventHandled (whereas Closing isn't). Settings an EventHandler doesn't work.
How can I solve this?
Edit: the only solution I can think of is to create a Dictionary of eventhandler wrappers when I add, so that I can get the same reference in remove. Any prettier solution?
Subscribe to the Loaded event of Ref and raise your own custom event when it's raised:
public event EventHandler Loaded;
...
Ref.Loaded += (ss, ee) => Loaded?.Invoke(this, EventArgs.Empty);
I ended up doing this.
public event EventHandler? Loaded
{
add
{
if (value != null)
{
var handler = new RoutedEventHandler((s, e) => value.Invoke(s, e));
_loadedHandlers.Add(value, handler);
Ref.Loaded += handler;
}
}
remove
{
if (value != null)
{
Ref.Loaded += _loadedHandlers[value];
_loadedHandlers.Remove(value);
}
}
}
private Dictionary<EventHandler, RoutedEventHandler> _loadedHandlers = new();

How to Remove or hildent all Default event & property in userControle

Remove all Default event & property
Remove event Click,Load,MouseClick,DoubleClick in userControle
or hildent event
public event EventHandler Click
{
add { this.Click += value; }
remove { this.Click -= value; }
}
Error !!!>>>An unhandled exception of type 'System.StackOverflowException' occurred in WindowsFormsControlLibrary1.dll
this image sample
enter image description here
You can try overriding them and tagging them not browsable.
Here is an example with Click event :
[Browsable(false)]
public new event EventHandler Click
{
add { base.Click += value; }
remove { base.Click -= value; }
}

c# check if event is null

I have this event in a webservice:
public event FindProductsByCharacteristicsCompletedEventHandler FindProductsByCharacteristicsCompleted
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
_findProductsByCharacteristicsCompleted += value;
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
_findProductsByCharacteristicsCompleted -= value;
}
}
And im then checking if the event value is null with this later in the class:
private void OnFindProductsByCharacteristicsOperationCompleted(object arg)
{
var handler = _findProductsByCharacteristicsCompleted;
if (handler == null)
return;
handler(this, new FindProductsByCharacteristicsCompletedEventArgs(completedEventArgs.Results, completedEventArgs.Error, completedEventArgs.Cancelled, completedEventArgs.UserState));
}
Your event implementation looks like it is an endless recursion. You are using the property itself in its implementation.
Change it to this:
private FindProductsByCharacteristicsCompletedEventHandler
_findProductsByCharacteristicsCompleted;
public event FindProductsByCharacteristicsCompletedEventHandler
FindProductsByCharacteristicsCompleted
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
_findProductsByCharacteristicsCompleted += value;
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
_findProductsByCharacteristicsCompleted -= value;
}
}
And now, implement your method like this:
var handler = _findProductsByCharacteristicsCompleted;
if(handler == null)
return;
handler(this, new FindProductsByCharacteristicsCompletedEventArgs(...));
This has the advantage that it is thread-safe.
Even if someone detached the last handler from the event after you checked for null but before you actually raised the event, you would not get an exception, because you are operating on the unchanged local variable.

Unit Test Event Handler

I got this event handle and how can I do unit test for this
public class MyLearningEvent
{
private event EventHandler _Closed;
public event EventHandler Closed
{
add
{
_Closed -= value;
_Closed += value;
}
remove
{
_Closed -= value;
}
}
public void OnClosed()
{
if (_Closed != null) _Closed(this, EventArgs.Empty);
}
}
Just modified code so that much clear
Thanks
You should not unit test that code. It's a feature which is built into .NET. Your event handling is flawed imho.
add
{
_Closed -= value;
_Closed += value;
}
Probably means that your invokers don't keep track on if they have subscribed or not. That can lead to memory leaks: http://blog.naviso.fr/wordpress/wp-content/uploads/2011/11/MemoryLeaks-English.jpg
A more robust (and thread safe implementation) is:
public class MyLearningEvent
{
public event EventHandler Closed = delegate {};
public void TriggerClosed()
{
Closed(this, EventArgs.Empty);
}
}
But you should not let anyone else trigger that event (make the TriggerClosed private/protected)
Try this method. This assumes MyClass.Close() raises the MyClass.Closed event.
public void ClosedEventHandlerIsNotCalledAfterBeingRemoved()
{
MyLearningEvent Target = new MyLearningEvent();
EventHandler Target_Closed = new EventHandler((sender, e) => { Assert.Fail("Closed EventHandler was raised after being removed."); });
Target.Closed += Target_Closed;
Target.Closed -= Target_Closed;
Target.OnClosed();
}

CustomControl textBox Validating event and ComboBox

My CustomControl is created with TextBox and ComboBox. And i want to use Validating event for this control. But if i use innerTextBox.Validating this means that will work for TetBox which is ok. But i do not want that this event will fire when i will click on ComboBox which is also part of this UserControl. I want that this UC will be as one. So i can click on TextBox and Combobox and no event will fire becouse they are one together...
innerTextBox is TextBox
innereComboBox is ComboBox
this is my code code event for Validating. What to do that event will not fire when i click on ComboBox?
public new event System.ComponentModel.CancelEventHandler Validating
{
add
{
innerTextBox.Validating += value;
}
remove { innerTextBox.Validating -= value; }
}
Hope you understand my problem.
I think you have to do this yourself. Turn off the CausesValidation property for your inner controls so they DON'T fire, and then run your validating code for the UserControl:
public UserControl1() {
InitializeComponent();
innerTextBox.CausesValidation = false;
innerComboBox.CausesValidation = false;
}
For example, this control requires a non-empty TextBox and a selected item from the ComboBox:
protected override void OnValidating(CancelEventArgs e) {
if (innerTextBox.Text == string.Empty)
e.Cancel = true;
else if (innerComboBox.SelectedIndex == -1)
e.Cancel = true;
base.OnValidating(e);
}
Did you try adding combobox to validating event?
public new event System.ComponentModel.CancelEventHandler Validating
{
add
{
innerTextBox.Validating += value;
innerComboBox.Validating += value;
}
remove
{
innerTextBox.Validating -= value; }
innerComboBox.Validating -= value; }
}
}

Categories

Resources