我正在尝试从中派生一个类Gtk.Button
。我遇到了一个可以解决的障碍(根本不使用OnActivate
),但我无法解释,因此解决它可能不安全。
似乎覆盖继承自的OnActivate
方法会改变按钮的行为。Gtk.Button
Gtk.Widget
为什么会这样,我该如何预防?
实现这种效果的唯一方法是一些丑陋的基于反射的检查。
这正是我所做的,您可以尝试什么来重现该问题:
这是一个包含自定义按钮类和该类的一个实例的小型 Gtk# 应用程序示例。OnActivate
在自定义按钮类中没有被覆盖。
using System;
using Gtk;
namespace ButtonOnActivateExample
{
class Program
{
private class MyButton : Button
{
public MyButton()
{
}
public MyButton(IntPtr raw)
{
}
}
[STAThread]
public static void Main(string[] args)
{
Application.Init();
using (Window win = new Window("OnActivate Test")) {
win.SetSizeRequest(300, 200);
win.Hidden += delegate(object sender, EventArgs e) {
Application.Quit();
};
MyButton btn = new MyButton();
btn.Clicked += delegate {
Console.WriteLine("clicked");
};
win.Add(btn);
win.ShowAll();
Application.Run();
win.Destroy();
}
}
}
}
单击按钮时,单击的单词将添加到控制台中的新行中。如果按钮被聚焦(通常是这种情况,因为它是窗口中唯一可聚焦的元素),并且用户按下空格键,同样会发生预期的情况(即触发Clicked
事件)。
在这个修改后的版本中,有一个细微的变化:MyButton
该类现在覆盖了该OnActivate
方法,但被覆盖的版本除了调用该方法的继承版本之外什么都不做:
using System;
using Gtk;
namespace ButtonOnActivateExample
{
class Program
{
private class MyButton : Button
{
public MyButton()
{
}
public MyButton(IntPtr raw)
{
}
protected override void OnActivate()
{
base.OnActivate();
}
}
[STAThread]
public static void Main(string[] args)
{
Application.Init();
using (Window win = new Window("OnActivate Test")) {
win.SetSizeRequest(300, 200);
win.Hidden += delegate(object sender, EventArgs e) {
Application.Quit();
};
MyButton btn = new MyButton();
btn.Clicked += delegate {
Console.WriteLine("clicked");
};
win.Add(btn);
win.ShowAll();
Application.Run();
win.Destroy();
}
}
}
}
这在语义上应该与第一个版本相同。然而,它并没有 - 莫名其妙地,应用程序的行为发生了变化!
文档只是说: “OnActivate
在子类中覆盖此方法以在小部件被激活时得到通知,通常是在用户在键导航期间按 Enter 或 Space 时。”
单击该按钮仍会触发该Clicked
事件。但是,按空格键不再起作用;控制台中什么也没有出现。
我可以使用 Gtk# for .NET、Windows 7 上的 Mono 和 Ubuntu 上的 Mono 始终如一地重现这种行为。
这里发生了什么?