【问题标题】:What's the Correct Way to Run Code After Event Handlers?在事件处理程序之后运行代码的正确方法是什么?
【发布时间】: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#


    【解决方案1】:

    在 Gtk+ 中,因此在 Gtk# 中就是这样。 Gtk.Button.OnClicked 被安装为信号的类处理程序。由于这个信号是“首先运行”类型的,处理程序在任何其他与之连接的回调之前运行。

    使用 C 中的 Gtk+,您有 g_signal_connect_after(),它注册了一个回调,该回调将在 类处理程序和其他回调被调用之后调用,但这似乎不适用于 Gtk#。

    在某些事情发生后运行代码的最简单方法是使用一次性 idle 回调。是的,它有点骇人听闻,但它适用于任何情况,甚至与 Gtk 信号无关:

    protected override void OnClicked()
    {
        Console.WriteLine("before");
        base.OnClicked();
        GLib.Idle.Add(delegate {
                    Console.WriteLine("after");
                    return false;
                });
    }
    

    【讨论】:

    • 似乎没有人知道一种可以调用正确的方法,这似乎是最好的解决方案。目前,我没有看到任何缺点或问题,所以我会接受这一点。
    猜你喜欢
    • 1970-01-01
    • 2012-05-15
    • 2012-07-22
    • 2012-03-31
    • 2016-02-03
    • 1970-01-01
    • 2018-08-25
    • 2015-02-11
    • 1970-01-01
    相关资源
    最近更新 更多