【问题标题】:Timer Tick after FormClosing?FormClosing后的计时器滴答声?
【发布时间】:2012-08-15 04:29:23
【问题描述】:

是否有任何可能在 myForm_FormClosing 之后调用 timer_Tick 在下面的代码中。

如果有机会:是否足以在 myForm_FormClosing 中调用 timer.Stop() 以避免在 myForm_FormClosing 之后调用 timer_Tick?

using System;
using System.Windows.Forms;
using System.ComponentModel;

namespace Test
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MyForm());
        }
    }

    class MyForm : Form
    {
        private IContainer components;
        private Timer timer;

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        public MyForm()
        {
            components = new Container();
            timer = new Timer(components);

            timer.Interval = 50;
            timer.Tick += timer_Tick;
            timer.Enabled = true;

            FormClosing += myForm_FormClosing;
        }

        private void timer_Tick(object sender, EventArgs e)
        {
        }

        private void myForm_FormClosing(object sender, FormClosingEventArgs e)
        {
        }
    }
}

更新: 在收到一些提示(感谢您的帮助)之后,我基本上选择了以下代码来实现我想要的。 请不要在调用 myForm_FormClosing 之后仍然可以调用 timer1_Tick! 这个解决方案只是引入了一个标志(我称之为 doWork),它会在调用 myForm_FormClosing 后停止 timer1_Tick 内的代码执行。

using System;
using System.Windows.Forms;
using System.ComponentModel;

namespace Test
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MyForm());
        }
    }

    class MyForm : Form
    {
        private IContainer components;
        private Timer timer;
        private bool  doWork = true;

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        public MyForm()
        {
            components = new Container();
            timer = new Timer(components);

            timer.Interval = 50;
            timer.Tick += timer_Tick;
            timer.Enabled = true;

            FormClosing += myForm_FormClosing;
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            if (doWork)
            {
                //do the work
            }
        }

        private void myForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            doWork = false;
        }
    }
}

【问题讨论】:

  • 是的,是的。如果 myForm_FormClosing 将是一个紧张的过程,请确保尽早停止计时器。此外,如果您取消关闭,请确保在必要时重新启动计时器。
  • @PowerRoy 是的,我已经尝试过了。在 myForm_FormClosing 之后没有调用 timer_Tick。但这并不能保证没有机会。
  • @J-Torres 感谢您的回答。但是你能解释一下为什么答案是肯定的。有没有这方面的文件。 (我没有为那个特殊情况找到任何东西。)
  • OP,@JPAlioto 提供了一个很好的例子来说明这种情况是如何发生的。
  • @JTorres 感谢您指出这一点。

标签: c# winforms


【解决方案1】:

是的,这是可能的。根据the docs...

在表单关闭之前发生。

当一个表单关闭时,它被释放,释放所有资源 与表单相关联。

在 FormClosing 事件之后才会释放计时器。这是一个非常人为的示例,说明了它是如何发生的。在调用 FormClosing 之后,您将看到在 Timer 滴答声上点击了调试器断点。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Threading;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private System.Windows.Forms.Timer _time = new System.Windows.Forms.Timer();
        private Task _t1 = null;
        private Task _t2 = null;
        private bool _closingFlag = false;
        public Form1()
        {
            InitializeComponent();

            _time.Interval = 50;
            _time.Tick += (s, e) => { 
                textBox1.Text = DateTime.Now.ToString();
                if (_closingFlag) Debugger.Break();
            };

            _time.Start();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            _closingFlag = true;

            _t1 = Task.Factory.StartNew(() => { Thread.Sleep(1000); });
            _t2 = Task.Factory.StartNew(() => { Thread.Sleep(1000); });

            Task.WaitAll(_t1, _t2);
        }
    }
}

【讨论】:

  • Mmmh ... 似乎如果我在 Form1_FormClosing 中最后调用 _time.Stop() ,则 Tick-Method 不会上升。有人可以确认吗?
  • @thiel 不管你做什么,这仍然是一个竞争条件。如果您遇到了必须完成的并发,您需要使用普通的多线程方法来处理它。
  • 好的。我想我只是在 Form1_FormClosing 中设置了一个标志,该标志在 Tick-EventHandler 中进行检查,以避免执行我不想执行的事情。大家对此怎么看?
  • 我认为System.Windows.Forms.Timer 不会发生这种情况。
  • @LuisQuijada 对不起,我不明白你的意思。
【解决方案2】:

如果您使用计时器System.Windows.Forms.Timer,UI 线程必须处于空闲状态才能处理来自计时器的滴答声,因此据我了解这是不可能的。

如果您使用带有自己线程的计时器,则可能会发生这种情况,例如System.Timers.Timer。在这种情况下,我们可以通过实施类似这样的方法来避免您提到的内容:

class MyForm : Form
{
    private System.Timers.Timer timer;

    private Object justForLocking = new Object();
    private Boolean safeToProceed = true;

    [...]

    public MyForm()
    {
        components = new Container();
        timer = new System.Timers.Timer();

        timer.Interval = 50;
        timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
        timer.Start();

        FormClosing += myForm_FormClosing;
    }

    void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
         // In case that this code is being executed after
         // the method myForm_FormClosing has adquired the 
         // exclusive lock over our dummy resource,
         // the timer thread will wait until the resource if released.
         // Once is released, our control flag will be set to false
         // and the timer should just return and never execute again.
         lock(justForLocking)
         {
             if (safeToProceed)
             {
                 // Do whatever you want to do at this point
             }
         }
    }

    private void myForm_FormClosing(object sender, FormClosingEventArgs e)
    {
         lock(justForLocking)
         {
             safeToProceed = false;
         }
         timer.Stop();

         // Do something else
    }

    [...]
}

这个其他SO question有相关信息。

编辑: 上面的代码仅在使用 System.Timers.Timer 而不是 System.Windows.Forms.Timer 时才有效

【讨论】:

  • 为什么在同一个线程调用两个方法需要同步?
  • 你是对的。我混合了一些对其他类型的计时器有效的代码。我会编辑帖子。
【解决方案3】:

我不这么认为,但无论如何最好还是调用 timer.stop()。如果您需要它,但您应该在 program.cs 中创建计时器对象

【讨论】:

  • 请注意Stop() 不保证tick 不会马上调用回调。
  • 我不想在 Main-Method 中创建计时器(我猜你的意思是 program.cs)但在 Form1 中
  • 你可以用 bools 计算出一些东西来保证 tick 的功能只能在特定时间发生。
  • 我认为您不需要使用锁,我认为计时器与其余代码共享一个线程。
  • @user1580785 请带我看看顶部的更新部分。我想这就是你的意思。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-03
  • 1970-01-01
  • 2014-03-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多