我从Gtk.Button
派生一个类,该类应该在单击按钮时运行一些代码,但只有在用户定义的事件处理程序之后。
基于.NET约定,这不是问题。以下示例Windows窗体代码显示了System.Windows.Forms.Button
的子类,它在事件处理程序之前执行一些代码,然后调用事件处理程序(通过调用继承的OnClick
method;同样的使用System.Windows.Controls.Button.OnClick
)在WPF中工作,然后在事件处理程序之后执行一些代码:
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);
}
}
}
}
正如所料,输出是:
before
event
after
但是,到目前为止,我还没有在Gtk#中复制这种行为。与.NET约定相反,继承的OnClicked
method of Gtk.Button
似乎不会触发Clicked
event。实际上,文档将OnClicked
方法称为“默认处理程序”。
要验证Gtk#的行为有何不同,请参阅以下示例代码:
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();
}
}
}
}
不幸的是,输出是
before
after
event
即。甚至OnClicked
末尾的代码也已经在Clicked
事件处理程序之前运行。
我的问题是: Gtk#在事件处理程序之后只在事件上执行某些代码的正确方法是什么?
到目前为止,我找到了两个不满意的解决方法:
第一个是定义Clicked
事件的替代品,例如Clicking
事件(使用OnClicking
方法触发Clicking
事件处理程序)。我可以在我重写的OnClicking
版本中调用OnClicked
,从而在我喜欢的事件处理程序之前和之后运行代码。此外,我的按钮类的任何子类都可以按预期方式使用OnClicking
,即在base.OnClicking
事件处理程序运行时调用Clicking
。
这不是很干净,因为没有什么可以阻止我的按钮类的用户使用原始的Clicked
事件注册他们的事件处理程序而不是正确嵌入到事件中的新Clicking
事件按钮的逻辑。特别是,我甚至无法修改继承的Clicked
事件的API文档,以表示不应使用Clicked
,用户应转而使用Clicking
。
其他解决方法仅适用于此特定情况,因为恰好在Clicked
事件处理程序之后始终执行OnReleased
method。我可以使用该方法插入一些保证仅在任何Clicked
事件处理程序之后运行的代码,但很明显,此解决方案无法转移到其他事件不方便的事件。
答案 0 :(得分:1)
在Gtk +中,因此在Gtk#中就是这样。 Gtk.Button.OnClicked
作为信号的类处理程序安装。由于此信号属于“Run First”类型,因此处理程序在连接到它的任何其他回调之前运行。
使用来自C的Gtk +你有g_signal_connect_after()
在类处理程序和其他回调被调用之后注册一个被称为的回调,但这似乎不适用于Gtk #。
在经过一些事情之后运行代码的最简单方法是使用和一次空闲回调。是的,它有点hackish,但它适用于任何情况,甚至与Gtk信号无关:
protected override void OnClicked()
{
Console.WriteLine("before");
base.OnClicked();
GLib.Idle.Add(delegate {
Console.WriteLine("after");
return false;
});
}