Calling C# events from outside the owning class?

22,136

Solution 1

You just need to add a public method for invoking the event. Microsoft already does this for some events such as PerformClick for controls that expose a Click event.

public class CustomGUIElement    
{
    public void PerformClick()
    {
        OnClick(EventArgs.Empty);
    }

    protected virtual void OnClick(EventArgs e)
    {
        if (Click != null)
            Click(this, e);
    }
}

You would then do the following inside your example event handler...

public void CustomForm_Click(object sender, MouseEventArgs e)        
{
    _elements[0].PerformClick();
}

Solution 2

The event keyword in c# modifies the declaration of the delegate. It prevents direct assignment to the delegate (you can only use += and -= on an event), and it prevents invocation of the delegate from outside the class.

So you could alter your code to look like this:

public class CustomGUIElement
{
...
    public MouseEventHandler Click;
    // etc, and so forth.
...
}

Then you can invoke the event from outside the class like this.

myCustomGUIElement.Click(sender,args);

The drawback is that code using the class can overwrite any registered handlers very easily with code like this:

myCustomGUIElement.Click = null;

which is not allowed if the Click delegate is declared as an event.

Solution 3

You can shorten the code suggested in the accepted answer a lot using the modern syntax feature of the .NET framework:

public event Action<int> RecipeSelected;
public void RaiseRecpeSelected(int recipe) => RecipeSelected?.Invoke(recipe);

Solution 4

You really should wrap the code you want to be able to execute from the outside in a method. That method can then do whatever your event would do - and that event would also instead call that method.

Share:
22,136
Matthew Scharley
Author by

Matthew Scharley

Email: [email protected]

Updated on July 05, 2022

Comments

  • Matthew Scharley
    Matthew Scharley almost 2 years

    Is it possible under any set of circumstances to be able to accomplish this?

    My current circumstances are this:

    public class CustomForm : Form
    {
        public class CustomGUIElement
        {
        ...
            public event MouseEventHandler Click;
            // etc, and so forth.
        ...
        }
    
        private List<CustomGUIElement> _elements;
    
        ...
    
        public void CustomForm_Click(object sender, MouseEventArgs e)
        {
            // we might want to call one of the _elements[n].Click in here
            // but we can't because we aren't in the same class.
        }
    }
    

    My first thought was to have a function similar to:

    internal enum GUIElementHandlers { Click, ... }
    internal void CustomGUIElement::CallHandler(GUIElementHandler h, object[] args) {
        switch (h) {
            case Click:
                this.Click(this, (EventArgs)args[0]);
                break;
            ... // etc and so forth
        }
    }
    

    It's a horribly ugly kludge, but it should work... There must be a more elegant solution though? The .NET library does this all the time with message handlers and calling events in Control's. Does anyone else have any other/better ideas?