views:

2005

answers:

3

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?

A: 

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.

Per Hornshøj-Schierbeck
It'd work. Poorly, but it'd work. Storing a list of callbacks is essentially what an event does anyway. Why go the effort of reimplementing what's already there?
Matthew Scharley
+16  A: 

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();
}
Phil Wright
I think he ment raising the event from outside the events class?
Per Hornshøj-Schierbeck
You call PerformClick() from outside the events class.
Paul Batum
No, this is the style of thing I was looking to do; ie. calling the event from outside the event's class. I was just hoping there was a way to avoid the method. I suppose I'll go with the internal solution I posted, this custom form will be in a DLL, so the internal stuff will be hidden.
Matthew Scharley
I'd opt for the cleaner solution posted here, making PerformClick internal if you don't want it exposed. My feelings on using the enum and the CallHandler method is that it will be harder to read/maintain later.
Craig Eddy
+2  A: 

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.

Lee
I hadn't thought about it like that. The other answer is still more practical, but thanks for the insight.
Matthew Scharley