Application.Run(),Application.Exit()和计时器

时间:2012-11-02 12:52:09

标签: c# timer scheduled-tasks message-loop

我有一个winforms应用程序,我将通过任务调度程序调用它来下载文件并将它们插入到数据库中。但是,当文件可用时,它是不可预测的,所以我使用计时器(System.Windws.Forms.Timer)来轮询文件。

 static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            if (args != null && args.Length > 0)
            {

                Form1 f1 = new Form1();
                if (f1.IsLive)
                {
                    f1.OnLaunch(); // tests DB connection and reads and updates the expiry date list.

                    if (args[0] == "FullStats")
                        f1.FullStatsDataPump();
                    else if (args[0] == "OptionsStats")
                    {
                        f1.OptionsStatsTimer_Tick(null, null);
                        f1.OptionsStatsTimer.Start();
                    }
                    else if (args[0] == "OptionsTraded")
                    {
                        f1._optionsTradedTimer_Tick(null, null);
                        f1.OptionsTradedTimer.Start();
                    }
                    else
                    {
                        EmailManager.InvalidInputArgument(args[0]);
                        Application.Exit();
                    }

                    Application.Run();
                }

            }

在上面的代码段中,OptionsTradedTimer / OptionsStatsTimer都会轮询文件,然后开始以Application.Exit()结尾的流程。这完全运行但后来它陷入了无限的消息循环。我认为Application.Run()会在第一个计时器滴答后立即被调用,因此当Application.Exit()最终被调用时,它将结束消息循环。但是如果我逐步执行代码,那么在Application.Exit()之后程序返回到它所在的timer.tick(),然后继续到底部的Application.Run()。底部的Application.Run()是必要的,因为没有它,计时器只会打勾一次然后应用程序将退出。

那么如何正确告诉应用程序退出?或者我应该在哪里打电话Application.Run()

4 个答案:

答案 0 :(得分:0)

这听起来有些奇怪 - 也许您应该简单地将Application.exit移动到一个单独的过程,如果需要退出程序,只需更改一些布尔变量。在主程序中,您可以等待布尔值更改,然后退出程序一次。另外,你可以在开始时将boolean变量设置为false,这样你就不需要运行了。

答案 1 :(得分:0)

我认为您不需要使用Application.Exit()。您的Main()方法是应用程序的入口点;当它返回时,应用程序退出。一般来说,Application.Run()用于启动运行直到关闭的窗体。尝试一下这段代码 - 我没有测试过它,但它应该做你想要的。

using System.Linq;
using System.Threading;

class MyApplication
{
    [STAThread]
    static void Main(string[] args)
    {
        const string ARG_SHOWFORM = "ShowForm";
        const string ARG_STATS = "OptionsStats";
        const string ARG_TRADED = "OptionsTraded";

        if (args.Contains(ARG_SHOWFORM) || args.Length == 0) {
            Application.Run(new Form1());  //This will block until the form is closed.

            //Make sure all your supporting logic is placed into the Form.Loaded event on the form (i.e.
            //get it out of the Main() method).

            return;
        }

        if (args.Contains(ARG_STATS))
            OptionsStatsMethod();

        else if (args.Contains(ARG_TRADED))
            OptionsTradedMethod();

        else
            EmailManager.InvalidInputArgument(args[0]);

    }

    private void OptionsTradedMethod()
    {
        while (true) {
            if (downloadSuccessful) //Use a method here that returns a boolean if the download succeeded.
                break;
            else
                Thread.Sleep(DEFAULT_WAIT_TIME_MS);
        }
    }

    private void OptionsStatsMethod()
    {
        while (true) {
            if (downloadSuccessful)  //Use a method here that returns a boolean if the download succeeded.
                break;
            else
                Thread.Sleep(DEFAULT_WAIT_TIME_MS);
        }
    }
}

答案 2 :(得分:0)

无法删除问题,所以不妨回答。

如果计时器在第一次运行时到达Application.Exit()行,则只会出现此问题。 (即,如果文件在程序运行时已经可用)。在这种情况下,在Application.Exit()之前调用Application.Run(),好像计时器在第一次运行时没有到达Application.Exit()(即文件尚未可用),然后Application.Run()获得被叫,而Application.Exit()稍后才被调用。

所以为了解决这个问题,我只是在计时器的滴答方法中添加了一个条件,以确保它们在第一次运行时没有这么做。

我不同意重组程序的方式我可以通过任务调度程序运行它来每天下载文件而没有表单和轮询功能,我也可以通过VS运行它作为正常的winforms带有按钮的应用程序,用于在出现问题时测试,调试和下载文件。

答案 3 :(得分:-1)

要保持主方法运行(保持线程处于活动状态),可以使用Thread.Sleep而不是Application.Run()。试试这个:

Thread.Sleep(System.Threading.Timeout.Infinite);

而不是Application.Exit()使用:

Process.GetCurrentProcess().Kill();

这种方式有效,但考虑使用Windows服务。