Events 什么';在事件处理程序之后运行代码的正确方法是什么?
我从Events 什么';在事件处理程序之后运行代码的正确方法是什么?,events,event-handling,gtk#,Events,Event Handling,Gtk#,我从Gtk.Button派生了一个类,该类应该在单击按钮时运行一些代码,但只能在用户定义的事件处理程序之后运行 基于.NET约定,这不会是一个问题。下面的示例性Windows窗体代码显示了System.Windows.Forms.Button的子类,该子类在事件处理程序之前执行一些代码,然后调用事件处理程序(通过调用继承的;在WPF中也适用),然后在事件处理程序之后执行一些代码: using System; using System.Windows.Forms; using System.Dra
Gtk.Button
派生了一个类,该类应该在单击按钮时运行一些代码,但只能在用户定义的事件处理程序之后运行
基于.NET约定,这不会是一个问题。下面的示例性Windows窗体代码显示了System.Windows.Forms.Button
的子类,该子类在事件处理程序之前执行一些代码,然后调用事件处理程序(通过调用继承的;在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方法称为“默认处理程序” 为了验证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
i、 e.甚至在单击事件处理程序之前,OnClicked
末尾的代码也已经运行
我的问题是:在Gtk中,只有在事件处理程序之后才对事件执行某些代码的正确方法是什么?
到目前为止,我发现了两个令人不满意的解决办法:
第一种方法是定义Clicked
事件的替换,例如Clicking
事件(使用相应的OnClicking
方法触发Clicking
事件处理程序)。我可以在被重写的OnClicked
版本中调用onclick
,从而在事件处理程序之前和之后运行代码。此外,button类的任何子类都可以按预期的方式使用OnClicking
,即在单击事件处理程序应该运行时调用base.OnClicking
但这并不是很干净,因为没有任何东西可以阻止button类的用户将其事件处理程序注册到原始的Clicked
事件中,而不是注册到按钮逻辑中正确嵌入的新Clicking
事件中。特别是,我甚至无法修改继承的Clicked
事件的API文档,以表示不应该使用Clicked
,用户应该转而使用Clicking
另一种解决方法仅在这种特定情况下有效,因为在单击事件处理程序之后,总是会执行一个。我可以使用该方法插入一些代码,这些代码保证只在单击任何事件处理程序后运行,但显然,此解决方案无法转移到不方便跟随其他事件的事件中。在Gtk+中,因此在Gtk中是这样的Gtk.Button.OnClicked
作为信号的类处理程序安装。由于该信号属于“Run First”类型,因此处理程序在连接到它的任何其他回调之前运行
使用C中的Gtk+,您就有了g_signal\u connect\u after()
,它注册了一个回调,以便在调用类处理程序和其他回调之后调用,但这似乎对Gtk不可用
传递后运行代码的最简单方法是使用一次空闲回调。是的,这有点黑客,但它适用于任何情况,即使与Gtk信号无关:
protected override void OnClicked()
{
Console.WriteLine("before");
base.OnClicked();
GLib.Idle.Add(delegate {
Console.WriteLine("after");
return false;
});
}
因为似乎没有人知道一种可以称之为正确的方法,所以这似乎是最好的解决方案。现在,我没有看到任何缺点或缺陷,所以我会接受这一点。