Форма не отвечает, когда любая другая операция выполняется в C # - PullRequest
9 голосов
/ 07 февраля 2011

У меня есть форма (разработанная в C # с использованием VS2010) с индикатором выполнения.Это своего рода форма секундомера, где я заполняю индикатор выполнения, скажем, в 10 сек ... По истечении времени индикатор выполнения заполняется соответствующим образом ... Означает, что через 5 сек индикатор выполнения заполняется на 50% и т. Д. *

Я использовал цикл for для выполнения этой операции: -

for(int count=0;count<200;count++)
{
   progbar.performstep();
   progbar.update();
   update();
   Thread.Sleep(50);
}

Я использовал Thread.Sleep 50 мсек, чтобы индикатор выполнения обновлялся плавно.На 1сек он увеличивается с шагом.

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

Спасибо за помощь и извините за использование такого сложного языка.

С уважением,Swanand

Обновление : я решил эту проблему с помощью приведенных ниже ответов. Одна распространенная ошибка, которую я узнал, - это забыть "Applications.DoEvents()" вместе с "update()".... Если вы введете эту строку, у вас будет меньше шансов стать "повешенным"!

Ответы [ 5 ]

14 голосов
/ 07 февраля 2011

Вы выполняете длительную операцию в потоке пользовательского интерфейса, что означает, что «цикл сообщений» пользовательского интерфейса (отвечающий за обработку таких событий, как ввод данных пользователем и обновление экрана) не получает возможности для запуска.

Вы должны выполнить длительную операцию в другом потоке (независимо от того, создаете ли вы себя или фоновый поток) и либо использовать BackgroundWorker, чтобы легко обновить индикатор выполнения, либо использовать Control.Invoke/BeginInvoke Маршалл делегат обратного вызова в потоке пользовательского интерфейса, когда вам нужно обновить пользовательский интерфейс. (Вы не должны обновлять элементы управления из неправильного потока.)

Если ваше единственное взаимодействие с пользовательским интерфейсом заполняет индикатор выполнения, я предлагаю использовать BackgroundWorker.

Если вы на самом деле не выполняете «настоящую» работу, просто ждете, пока пройдет время, вы можете использовать System.Windows.Forms.Timer вместо всего этого, однако. Это будет «галочка» в потоке пользовательского интерфейса, но не будет блокировать поток между тиками. Вы должны использовать это, только если у вас нет много работы, хотя - если он действительно просто обновляет индикатор выполнения, а не (скажем) обрабатывает файл и т. Д. Обратите внимание, что вы не должны полагайтесь на срабатывание таймера точно «вовремя» - вам, вероятно, следует установить положение индикатора выполнения на основе наблюдаемого времени, а не наблюдаемого количества тактов.

7 голосов
/ 07 февраля 2011

Вы блокируете поток пользовательского интерфейса, что означает, что он не обрабатывает такие события, как «рисование».Чтобы сделать это правильно, вы должны использовать что-то вроде BackgroundWorker и просто обновлять пользовательский интерфейс из события progress.

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

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

class MyForm : Form
{
    Button btn;
    BackgroundWorker worker;
    ProgressBar bar;
    public MyForm()
    {
        Controls.Add(btn = new Button { Text = "Click me" });
        btn.Click += new EventHandler(btn_Click);

        Controls.Add(bar = new ProgressBar { Dock = DockStyle.Bottom, Visible = false, Minimum = 0, Maximum = 100 });

        worker = new BackgroundWorker { WorkerReportsProgress = true };
        worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
        worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    }

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        bar.Visible = false;
        if (e.Error != null)
        {
            Text = e.Error.Message;
        }
        else if (e.Cancelled)
        {
            Text = "cancelled";
        }
        else
        {
            Text = e.Result == null ? "complete" : e.Result.ToString();
        }
        btn.Enabled = true;
    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int count = 0; count < 100; count++)
        {
            worker.ReportProgress(count);
            Thread.Sleep(50);
        }
    }

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        bar.Value = e.ProgressPercentage;
    }

    void btn_Click(object sender, EventArgs e)
    {
        bar.Value = 0;
        bar.Visible = true;
        btn.Enabled = false;
        worker.RunWorkerAsync();
    }
}
2 голосов
/ 07 февраля 2011

Вы блокируете основной поток пользовательского интерфейса. Вы можете использовать фоновый рабочий для этого. Вы можете найти более подробную информацию в MSDN

0 голосов
/ 07 февраля 2011

Если вы хотите запустить свой код, вы должны поместить этот код в функцию и вызвать эту функцию с одним потоком.

 public static void fun1()
        {
            for (int i = 0; i <= 10; i++)
            {
                Console.Write("This is function1");
                Console.Write("\n");

            }

        }
  Thread firstthread = new Thread(new ThreadStart(fun1));

  firstthread.Start();
  firstthread.suspend();//whenever you want your current control to stop.

b'caz Thread.sleep (100) остановит весь контекст, а не тот, который вам нужен ..

0 голосов
/ 07 февраля 2011

Ответ, предложенный Марком, поможет.Длительное выполнение операций может привести к сбою приложения или не отвечать на запросы.У меня есть запись в блоге, касающаяся использования фонового рабочего класса.

http://midnightprogrammer.net/post/Using-Background-Worker-in-C.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...