Quick answer:
[GLib.ConnectBefore]
protected virtual void AddButtonPressed(object sender, EventArgs e) {
Console.WriteLine("Button pressed");
for (uint i = 0; i < plus.Length; i++) {
if (sender.Equals(plus[i])) {
uint index = i;
i = (uint)plus.Length;
Console.WriteLine(index);
}
}
}
Rambling explanation:
This is actually an interesting question. It took a bit of searching to find, but GTK#'s FAQ (but I guess not frequently linked to) says,
"As of release 0.15, Gtk# started
using the CONNECT_AFTER flag when
connecting event handlers to signals.
This means that the event handlers are
not run until after the default signal
handlers, which means that the widget
will be updated when the event
handlers run. A side effect of this
change is that in the case where
default handlers return true to stop
signal propogation, Gtk# events will
not be emitted. This is the case for
example in Gtk.Button, where the
button-press-event default signal
handler is overridden to emit Pressed
events.
While potentially confusing, this is
not really a bug. When you use a
Gtk.Button, you are getting a widget
that emits Pressed events in response
to Button1 presses. If you also want
your Button to change colors, or popup
a context menu on Button3 presses,
that's not a Gtk.Button. The correct
way to implement such a widget is to
subclass Gtk.Button and override the
OnButtonPressEvent virtual method to
implement the new behaviors you
desire."
If it weren't for, "public outcry" (rarely a sign of a good interface), there would be no way to avoid this, except subclassing which is sometimes annoying in C# due to the lack of anonymous classes. But luckily, you're not the first person to have this issue. So that's where the GLib.ConnectBefore attribute comes in. It basically says, call this event handler first so the event isn't devoured by Gtk+.
The annoyance doesn't end there though. I originally was going to suggest applying a good proven solution to passing "extra" parameters to event handlers. In this case, this would allow you to find the index without using equals or the Name
string It basically involves creating a wrapper delegate that "pretends" to be a ButtonPressEventHandler but internally passes an int to your backing method:
Func<uint, ButtonPressEventHandler> indexWrapper = ((index) => ((s, e) => { AddButtonPressed_wrapped(s, e, index); }));
...
plus[i].ButtonPressEvent += indexWrapper(i);
...
protected virtual void AddButtonPressed_wrapped(object sender, EventArgs e, uint index)
{
Console.WriteLine("Button pressed");
Console.WriteLine("Index = {0}", index);
}
It compiles and runs without errors, but it has the same problem, the event never fires. I realized that you can't put an attribute directly on a delegate/lambda. So even though the backing method has [GLib.ConnectBefore]
the delegate doesn't, so it fails.
As a final note, you could use the Clicked event as in this API example. I verified that it works as expected. One would think that it would only fire on mouse-clicks, but it actually does fire on spacebar as well.