我正在尝试从Gtk.Button
派生一个班级。我遇到了一个障碍,我可以解决(完全不使用OnActivate
),但我无法解释,因此解决它可能是不安全的。
似乎覆盖Gtk.Button
从Gtk.Widget
继承的OnActivate
method会改变按钮的行为。
为什么会这样,我该如何预防呢?
实现这种效果的唯一方法是进行一些难看的基于反射的检查。
这正是我所做的,以及你可以尝试再现这个问题:
这是一个小样本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
event被触发)。
在此修改版本中,稍作修改: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();
}
}
}
}
这应该在语义上与第一个版本相同。然而,它并非 - 莫名其妙地,应用程序的行为已经改变了!
docs只是说OnActivate
:“在子窗口中覆盖此方法,以便在窗口小部件激活时得到通知,通常是在用户在键导航期间按下Enter或Space时。”
单击该按钮仍会触发Clicked
事件。但是,按空格键不再有效;控制台中没有任何内容。
我可以使用Gtk#for .NET,Windows 7上的Mono和Ubuntu上的Mono继续重现此行为。
这里发生了什么?
答案 0 :(得分:1)
这是一个有趣的问题。不幸的是,我无法就确切的原因给出明确的答案。即使我已经查看过gtk#源代码,我很快就会在默认信号处理程序,类和gtypes的丛林中迷失。
如果您只是在寻找解决方案,我可以告诉您:您应该覆盖OnActivated
方法(最后使用d
)。