Пользовательский интерфейс приложения WinForm зависает во время длительной работы
У меня есть приложение Windows Forms, в котором мне нужно использовать цикл for с большим количеством удаленных вызовов около 2000 - 3000 вызовов,
и выполняя цикл for, я теряю контроль над формой и элементами управления формой, так как это становится большим процессом, и некоторое время он показывает "Не отвечает", но если я долго жду, он снова возвращается, я думаю, что мне нужно использовать какая-то модель потоков для этого, есть идея, как я могу приступить к решению проблемы?
4 ответа
Вам необходимо выполнить длительную операцию в фоновом потоке.
Есть несколько способов сделать это.
Вы можете поставить в очередь вызов метода для выполнения в потоке пула потоков (см. Здесь):
ThreadPool.QueueUserWorkItem(new WaitCallback(YourMethod));
В.NET 4.0 вы можете использовать TaskFactory:
Task.Factory.StartNew(() => YourMethod());
А в.NET 4.5 и более поздних версиях вы можете (и должны, а не
TaskFactory.StartNew()
) использоватьTask.Run()
:Task.Run(() => YourMethod());
Вы можете использовать BackgroundWorker для большего контроля над методом, если вам нужны такие вещи, как обновления прогресса или уведомление о его завершении. Перетащите элемент управления BackgroundWorker на форму и присоедините свой метод к событию dowork. Затем просто запустите рабочий, когда вы хотите запустить свой метод. Конечно, вы можете создать BackgroundWorker вручную из кода, просто помните, что он требует удаления, когда вы закончите.
Создайте совершенно новую тему для вашей работы. Это наиболее сложный процесс, и он не нужен, если вам не нужен действительно точный контроль над потоком. Посмотрите страницу MSDN в классе Thread, если вы хотите узнать об этом.
Помните, что с чем угодно, вы не можете обновить GUI или изменить какие-либо элементы управления GUI из фонового потока. Если вы хотите что-то сделать в GUI, вы должны использовать Invoke (и InvokeRequired), чтобы вызвать метод обратно в потоке GUI. Смотрите здесь.
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 - самый простой способ.
Нет необходимости в нити. использование 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(). Вы можете найти его, чтобы понять, почему он работает и на что обращать внимание.
Очевидно, вам нужно использовать фоновые потоки. Я предлагаю вам прочитать эту бесплатную электронную книгу.