События не происходят в порядке - PullRequest
0 голосов
/ 19 сентября 2018

Я создаю приложение WinForms на C #.Когда я нажимаю кнопку, должен происходить определенный поток событий:

  • Нажмите кнопку
  • Показать метку1
  • Показать метку2
  • Вызов функции для анализа строки, введенной пользователем ранее (это может занять некоторое время в зависимости от строки)
  • Показать listBox1 и progressBar1
  • backgroundWorker1.RunWorkerAsync
  • backgroundWorker1_DoWork ()делает что-то x раз и сообщает о прогрессе каждый раз*

Но это не то, что на самом деле происходит.Когда я прослеживаю код и просматриваю форму, у него возникает несколько проблем.

  1. label1 и label2 фактически не появляются, пока не будет выполнен синтаксический анализ.
  2. progressBar1 только иногда обновляетсякак вызывается ProgressChanged.В других случаях он будет ждать до тех пор, пока не будет напечатано «DONE», и обновит все сразу.
  3. Каждый раз, когда progressChange () вызывается, вертикальная полоса прокрутки в listBox1 становится меньше, поэтому я могу сказать, что элементы добавляются, нотекст Предметов не появляется до тех пор, пока не напечатано «DONE».

Я новичок в использовании backgroundWorker, поэтому возможно, я просто не понимаю, как он должен функционировать.Но задержку показа ярлыков я просто не понимаю вообще.Нет ошибок, когда я прослеживаю код и строки, кажется, выполняются в правильном порядке.

У кого-нибудь есть идеи о том, что может быть причиной этих проблем?Буду признателен за любую помощь или совет.Я бы предпочел не публиковать свой код, просто потому, что его много, но если кому-то это нужно, чтобы лучше понять, просто lmk.

РЕДАКТИРОВАТЬ: Вот код.

private void button1_Click(object sender, EventArgs e){
    label1.Show();
    label2.Show();
    String errMsg = parseString();
    if (errMsg == ""){
        listBox1.Items.Clear();
        listBox1.Show();

        progressBar1.Maximum = 100;
        progressBar1.Step = 1;
        progressBar1.Value = 0;
        progressBar1.Show();

        backgroundWorker1.DoWork += backgroundWorker1_DoWork;
        backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
        backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
        backgroundWorker1.WorkerReportsProgress = true;
        backgroundWorker1.WorkerSupportsCancellation = true;

        if (backgroundWorker1.IsBusy != true)
        {
            backgroundWorker1.RunWorkerAsync();
        }
    }
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        backgroundWorker1.ReportProgress(1, "Updating Devices");
        for (int i = 0; i < 100; i++)
        {
            //todo: do stuff

            //update progress
            backgroundWorker1.ReportProgress(i, "Device:" + i);
        }
    }

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
        listBox1.Items.Add(e.UserState);
    }

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        MessageBox.Show("DONE");
    }

1 Ответ

0 голосов
/ 20 сентября 2018

Спасибо @HansPassant и @mjwills за их комментарии.Они привели меня на правильный путь и сделали возможным это решение.

В итоге я решил нанести двух фоновых рабочих, чтобы решить проблему с label1 и label2, которые не появляются до тех пор, пока не будет выполнен анализ.Я использую первый для разбора, а второй - для раздела «делать вещи».В коде, который вы увидите, мне пришлось использовать Invoke для редактирования меток, поскольку эта часть теперь существовала в другом потоке.

Я также понял, что «делать вещи» перед вызовом ProgressChanged не сразу.Я разрабатывал по частям и еще не реализовал этот код, но я знаю, что для выполнения этих действий потребуется не менее 3 секунд (отчасти потому, что используется пинг).Итак, сейчас я поместил вызов Sleep (3000) в этот цикл, чтобы смоделировать, как он будет себя вести.Это решило странное поведение progressbar1 и listbox1, которое было вызвано поглощением всей памяти.

Вот как получился код:

private void button1_Click(object sender, EventArgs e)
    {
        if (backgroundWorker1.IsBusy != true)
        {
            backgroundWorker1.RunWorkerAsync();
        }
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        String errMsg = parseString();
        if (errMsg == "")
        {
            if (listBox1.InvokeRequired)
            {
                listBox1.Invoke(new MethodInvoker(delegate
                {
                    listBox1.Items.Clear();
                    listBox1.Show();
                }));
            }

            if (progressBar1.InvokeRequired)
            {
                progressBar1.Invoke(new MethodInvoker(delegate
                {
                    progressBar1.Maximum = 100;
                    progressBar1.Step = 1;
                    progressBar1.Value = 0;
                    progressBar1.Show();
                }));
            }

            if (backgroundWorker2.IsBusy != true)
            {
                backgroundWorker2.RunWorkerAsync();
            }
        }
        else
        {
            MessageBox.Show(errMsg);
        }
    }

    private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
    {
        backgroundWorker2.ReportProgress(1, "Updating Devices");
        for (int i = 0; i < 100; i++)
        {
            System.Threading.Thread.Sleep(3000);
            //do stuff

            backgroundWorker2.ReportProgress(i, "Device:" + i);
        }
    }

    private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        if (progressBar1.InvokeRequired)
        {
            progressBar1.Invoke(new MethodInvoker(delegate
            {
                progressBar1.Value = e.ProgressPercentage;
            }));
        }
        if (listBox1.InvokeRequired)
        {
            listBox1.Invoke(new MethodInvoker(delegate
            {
                listBox1.Items.Add(e.UserState);
            }));
        }
    }

    private void backgroundWorker2_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        MessageBox.Show("DONE");
    }
...