I am deriving a class from Gtk.Button
that is supposed to run some code when the button is clicked, but only after the user-defined event handlers.
Based on .NET conventions, this wouldn't be a problem. The following exemplary Windows Forms code shows a subclass of System.Windows.Forms.Button
that executes some code before the event handlers, then invokes the event handlers (by calling the inherited OnClick
method; the same would work in WPF with System.Windows.Controls.Button.OnClick
), and then executes some code after the event handlers:
using System;
using System.Windows.Forms;
using System.Drawing;
namespace ButtonClickedTestSWF
{
class Program
{
private class MyButton : Button
{
protected override void OnClick(EventArgs e)
{
Console.WriteLine("before");
base.OnClick(e);
Console.WriteLine("after");
}
}
[STAThread]
public static void Main(string[] args)
{
using (Form win = new Form() {
Text = "Test"
}) {
win.StartPosition = FormStartPosition.CenterScreen;
win.Size = new Size(300, 200);
MyButton btn = new MyButton();
btn.Text = "Button";
btn.Click += delegate {
Console.WriteLine("event");
};
btn.Dock = DockStyle.Fill;
btn.Parent = win;
Application.Run(win);
}
}
}
}
As expected, the output is:
before
event
after
However, I have so far failed to replicate this behaviour in Gtk#. Contrary to .NET conventions, the inherited OnClicked
method of Gtk.Button
does not seem to fire the Clicked
event. In fact, the docs call the OnClicked
method a "default handler".
To verify that Gtk# behaves differently, here's some sample code:
using System;
using Gtk;
namespace ButtonClickedTest
{
class Program
{
private class MyButton : Button
{
public MyButton()
{
}
public MyButton(IntPtr raw) : base(raw)
{
}
protected override void OnClicked()
{
Console.WriteLine("before");
base.OnClicked();
Console.WriteLine("after");
}
}
[STAThread]
public static void Main(string[] args)
{
Application.Init();
using (Window win = new Window("Test")) {
win.WindowPosition = WindowPosition.Center;
win.SetSizeRequest(300, 200);
win.Hidden += delegate(object sender, EventArgs e) {
Application.Quit();
};
MyButton btn = new MyButton();
btn.Add(new Label("Button"));
btn.Clicked += delegate {
Console.WriteLine("event");
};
win.Add(btn);
win.ShowAll();
Application.Run();
}
}
}
}
Unfortunately, the output is
before
after
event
i.e. even code at the end of OnClicked
runs already before the Clicked
event handlers.
My question is: What is the proper way in Gtk# to execute some code upon an event only after the event handlers?
I have found two dissatisfying workarounds so far:
The first is to define a replacement for the Clicked
event, say, a Clicking
event (with an according OnClicking
method that fires the Clicking
event handlers). I could invoke OnClicking
in my overridden version of OnClicked
and thus run code before and after the event handlers as I like. Additionally, any subclasses of my button class could use OnClicking
in the expected way, i.e. calling base.OnClicking
when the Clicking
event handlers should run.
This is not very clean, though, because nothing would prevent users of my button class from registering their event handlers with the original Clicked
event rather with the new Clicking
event that is properly embedded into the button's logic. In particular, I could not even modify the API documentation for the inherited Clicked
event to express there that Clicked
should not be used and users should turn to Clicking
instead.
The other workaround works only in this specific case, as there happens to be an OnReleased
method that is always executed after the Clicked
event handlers. I could use that method to insert some code that is guaranteed to run only after any Clicked
event handlers, but obviously, this solution couldn't be transferred to events that are not conveniently followed by some other events.