Application.Run(), Application.Exit() и таймеры

У меня есть приложение 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()?


person Dan    schedule 02.11.2012    source источник
comment
Application.Exit() не приводит к завершению программы. Программа завершается, когда функция Main() возвращается. msdn.microsoft .com/en-us/library/ Application.Run() создает цикл обработки сообщений (бесконечный цикл), который прерывается при вызове Application.Exit(). Причина, по которой это не работает, заключается в том, что код не имеет логического смысла. Поэтому вам необходимо перепроектировать ваше приложение.   -  person theMayer    schedule 02.11.2012
comment
Проблема решена. Все, что мне нужно было сделать, это убедиться, что метод отсчета таймера не вызывает Application.Exit() при первом отсчете. Я собираюсь удалить этот вопрос в понедельник, так как не вижу, как это решение когда-либо будет полезно кому-либо еще. Спасибо всем.   -  person Dan    schedule 02.11.2012
comment
Звучит отлично. Я все еще думаю, что вы хотите пересмотреть свой дизайн. :-)   -  person theMayer    schedule 02.11.2012


Ответы (4)


Это звучит несколько странно - возможно, вам следует просто переместить Application.exit в отдельную процедуру и просто изменить какую-нибудь логическую переменную, если вам нужно выйти из программы. В вашей основной программе вы можете дождаться изменения логического значения, а затем один раз выйти из программы. Кроме того, вы можете установить логическую переменную в false в начале, чтобы вам не требовался запуск.

person Christian Sauer    schedule 02.11.2012

Я не думаю, что вам нужно использовать 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);
        }
    }
}
person theMayer    schedule 02.11.2012
comment
Это никогда не выйдет, потому что форма не будет отображаться при использовании планировщика задач. Форма просто обеспечивает приятный интерфейс для тестирования и отладки. - person Dan; 02.11.2012
comment
Как насчет того, чтобы добавить в программу опцию для отображения формы через командную строку? Как я уже сказал, я думаю, что это должно быть переработано, чтобы заставить его делать то, что вы хотите. - person theMayer; 02.11.2012
comment
Я не хочу, чтобы форма отображалась, и я не думаю, что она все равно будет отображаться при запуске через планировщик. Форма предназначена для того, когда я запускаю ее через VS, но мне также нужно ежедневно запускать ее через планировщик задач. Я не понимаю, как я могу избавиться от таймеров? Для меня наиболее разумным редизайном является сделать его службой Windows, но я действительно не хочу этого делать, я почти уверен, что это можно довольно легко исправить. Это просто вопрос понимания времени между таймерами и application.run() - person Dan; 02.11.2012
comment
Я поработаю над набором псевдокодов для вас, чтобы вы могли понять, о чем я говорю. - person theMayer; 02.11.2012

Не могу удалить вопрос, поэтому мог бы также ответить на него.

Проблема возникает только в том случае, если таймер достигает строки Application.Exit() при первом запуске. (т.е. если файл уже доступен при запуске программы). В этом случае Application.Exit() вызывается перед Application.Run(), где, как если бы таймер не достиг Application.Exit() при первом запуске (т.е. файл еще не доступен), тогда Application.Run() вызывается, а Application.Exit() вызывается позже.

Поэтому, чтобы решить эту проблему, я просто добавил условие в методы тика таймеров, чтобы убедиться, что они ничего не делают при первом запуске.

Я не согласен с реструктуризацией программы в ее нынешнем виде. Я могу запускать ее через планировщик задач для ежедневной загрузки файлов без формы и с функцией опроса, а также могу запускать ее через VS как обычное приложение winforms с кнопками. для тестирования, отладки и загрузки файлов, когда что-то пошло не так.

person Dan    schedule 05.11.2012

Чтобы ваш основной метод работал (поддерживал его поток), вы можете использовать Thread.Sleep вместо Application.Run(). Попробуй это:

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

и вместо Application.Exit() используйте:

Process.GetCurrentProcess().Kill();

Таким образом, это работает, но рассмотрите возможность использования для этого служб Windows.

person VahidNaderi    schedule 02.11.2012
comment
Спасибо. Значит ли это, что таймеры будут продолжать срабатывать? А также как мне сказать программе завершиться, когда я этого захочу? - person Dan; 02.11.2012
comment
Если вы используете Thread.Sleep в потоке Main(), вы приведете к зависанию программы. - person theMayer; 02.11.2012
comment
Он не будет зависать, когда запущены другие потоки (таймеры здесь). Пожалуйста, попробуйте. - person VahidNaderi; 02.11.2012