【发布时间】:2013-01-20 12:50:14
【问题描述】:
我从Gtk.Button 派生了一个类,它应该在单击按钮时运行一些代码,但仅在用户定义的事件处理程序之后。
基于 .NET 约定,这不是问题。以下示例性 Windows 窗体代码显示了 System.Windows.Forms.Button 的子类,它在事件处理程序之前执行一些代码,然后调用事件处理程序(通过调用继承的 OnClick method;同样适用于 WPF System.Windows.Controls.Button.OnClick),然后在事件处理程序之后执行一些代码:
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 事件(使用触发Clicking 事件处理程序的相应OnClicking 方法)。我可以在OnClicked 的覆盖版本中调用OnClicking,从而在我喜欢的事件处理程序之前和之后运行代码。此外,我的按钮类的任何子类都可以按预期方式使用OnClicking,即在Clicking 事件处理程序应该运行时调用base.OnClicking。
不过,这不是很干净,因为没有什么可以阻止我的按钮类的用户使用原始Clicked 事件而不是使用正确嵌入到按钮逻辑中的新Clicking 事件来注册他们的事件处理程序。特别是,我什至无法修改继承的 Clicked 事件的 API 文档,以在其中表示不应使用 Clicked,而用户应转而使用 Clicking。
另一种解决方法仅在这种特定情况下有效,因为恰好有一个 OnReleased method 总是在 Clicked 事件处理程序之后执行。我可以使用该方法插入一些保证仅在任何Clicked 事件处理程序之后运行的代码,但显然,此解决方案无法转移到其他一些事件不方便遵循的事件。
【问题讨论】:
标签: events event-handling gtk#