Пользовательский интерфейс приложения WinForm зависает во время длительной работы - PullRequest
24 голосов
/ 01 августа 2009

У меня есть приложение Windows Forms на котором мне нужно использовать цикл for с большим количеством удаленных вызовов около 2000 - 3000 вызовов,

и, выполняя цикл for, я теряю контроль над формой и элементами управления формой, так как это становится большим процессом, и некоторое время он показывает «Не отвечает», но если я долго жду, он снова возвращается, я думаю, что для этого нужно использовать какую-то модель многопоточности, есть ли идея, как я могу приступить к решению проблемы?

Ответы [ 4 ]

50 голосов
/ 01 августа 2009

Вам необходимо выполнить длительную операцию в фоновом потоке.

Есть несколько способов сделать это.

  1. Вы можете поставить вызов метода для выполнения в потоке пула потоков (см. здесь ):

    ThreadPool.QueueUserWorkItem(new WaitCallback(YourMethod));
    

    В .NET 4.0 вы можете использовать TaskFactory :

    Task.Factory.StartNew(() => YourMethod());
    

    А в .NET 4.5 и более поздних версиях вы можете (и должны вместо TaskFactory.StartNew()) использовать Task.Run():

    Task.Run(() => YourMethod());
    
  2. Вы можете использовать BackgroundWorker для большего контроля над методом, если вам нужны такие вещи, как обновления прогресса или уведомление о его завершении. Перетащите элемент управления BackgroundWorker на форму и присоедините свой метод к событию dowork. Затем просто запустите рабочий, когда вы хотите запустить свой метод. Конечно, вы можете создать BackgroundWorker вручную из кода, просто помните, что он требует удаления после завершения работы.

  3. Создайте совершенно новую тему для вашей работы. Это наиболее сложный процесс и он не нужен, если вам не нужен действительно точный контроль над потоком. См. Страницу MSDN класса Thread , если вы хотите узнать об этом.

Помните, что с любым потоком вы не можете обновить графический интерфейс или изменить какие-либо элементы управления графического интерфейса из фонового потока. Если вы хотите что-то сделать в GUI, вы должны использовать Invoke (и InvokeRequired), чтобы вызвать метод обратно в потоке GUI. См. здесь .

5 голосов
/ 26 июня 2010
    private voidForm_Load(object sender, EventArgs e)
    {
        MethodInvoker mk = delegate
        {
            //your job
        };
        mk.BeginInvoke(callbackfunction, null);
    }

    private void callbackfunction(IAsyncResult res)
    {
        // it will be called when your job finishes.
    }

использовать MethodInvoker - самый простой способ.

0 голосов
/ 26 июня 2010

Нет необходимости в потоке. Используйте Application.DoEvents(); //repaint or respond to msg Например:

foreach (DirectoryInfo subDir in dirInfo.EnumerateDirectories())
{
    count = count + 1;
    listBoxControl4.Items.Add(count.ToString() + ":" + subDir.FullName);
    Application.DoEvents(); //allow repaint to see status
    ProduceListing(subDir, " ");
}

Это будет проходить через все папки рекурсивно и записывать имена в список. Это может занять много времени. С DoEvents (), он будет показывать прогресс в каждом цикле. По сути, вызов позволяет окнам в этом потоке обновлять что-либо в цикле msg. Обязательно следите за непреднамеренной рекурсией, так как любой элемент управления в форме может быть снова нажат, даже если ваш первый еще не завершен. Это хорошо работает. (Это копия старого вызова Delphi Application.ProcessMessages (). Вы можете найти его, чтобы понять, почему он работает и на что обратить внимание.

0 голосов
/ 01 августа 2009

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

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