WinForm Application UI зависает во время длительной работы
У меня есть приложение для форм Windows
на котором мне нужно использовать цикл for, имеющий большое количество удаленных вызовов около 2000 - 3000 вызовов,
и, выполняя цикл for, я теряю контроль над элементами формы и формы, поскольку это становится большим процессом, и некоторое время он показывает "Не реагировать", но если я жду долго, он возвращается снова, я думаю, что я нужно использовать некоторую модель потоковой передачи для этого, есть ли какая-то идея, как я могу приступить к решению проблемы?
Ответы
Ответ 1
Вам нужно выполнить длительную операцию в фоновом потоке.
Есть несколько способов сделать это.
-
Вы можете запросить вызов метода для выполнения в потоке пула потоков (см. Здесь):
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, если вы хотите узнать об этом.
Помните, что с чем-либо с резьбой вы не можете обновить графический интерфейс или изменить какие-либо элементы управления графическим интерфейсом из фонового потока. Если вы хотите что-либо сделать в графическом интерфейсе, вы должны использовать Invoke (и InvokeRequired), чтобы вызвать метод обратно в потоке графического интерфейса. См. Здесь.
Ответ 2
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.
}
use MethodInvoker - самый простой способ.
Ответ 3
Очевидно, вам нужно использовать фоновые потоки. Я предлагаю вам читать эту бесплатную электронную книгу.
Ответ 4
Ничего не нужно. Используйте 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() он будет показывать прогресс в каждом цикле. В принципе, вызов позволяет окнам в этом потоке обновлять что-либо в цикле windows msg. Обязательно наблюдайте за непреднамеренной рекурсией, как любой элемент управления в форме, который нужно нажать, даже если ваш первый не завершился. Это хорошо работает. (Это копия старого вызова Delphi Application.ProcessMessages(). Вы можете найти это, чтобы понять, почему он работает и что нужно отслеживать.