Потоки позволяют вам выполнять тяжелые операции, в то время как вы продолжаете делать другие вещи.В случае пользовательских интерфейсов (ваш сценарий) асинхронное поведение почти всегда необходимо, так как блокировка потока пользовательского интерфейса приведет к тому, что пользователь не будет отвечать на запросы и просто не будет работать.
К счастью, ребята из Microsoftсделал чрезвычайно простым для написания того же кода, но в асинхронном режиме.Я обычно использую Задачи, потому что мне нравится элемент управления, который вы получаете над операцией, а также ContinueWith (), позволяющий вам контролировать то, что вы делаете с результатом, если вам нужно передать данные обратно в вызывающий поток.Если вы предпочитаете использовать потоки, ThreadPool.QueueUserWorkItem такой же простой.
Любая операция, которую вы не хотите блокировать потоком пользовательского интерфейса, оберните его следующим образом:
Task.Factory.StartNew(() => Object.PerformOperation());
или
ThreadPool.QueueUserWorkItem(new WaitCallback((x) => Object.PeroformOperation()));
Я считаю, что это позволяет мне писать точно такой же код, но без блокировки потока пользовательского интерфейса.Если у вас есть несколько операторов для выполнения, вы также можете использовать блок.
Task.Factory.StartNew(() =>
{
// do something
// do more stuff
// done
}).ContinueWith((completedTask) =>
{
// if you were computing a value with the task
// you can now do something with it
// this is like a callback method, but defined inline
// use ui's dispatcher if you need to interact with ui compontents
UI.Label.Dispatcher.Invoke(new Action(() =>
UI.Item.Label.Text = completedTask.Result;
}
Предстоящие асинхронные функции, которые будут выпущены в следующей версии .net, фактически упростят это еще больше!Но так как он использует задачи, вам все равно захочется освоиться с ними.
// this will begin the operation, then return control back to the ui so it does not hang.
var result = await Object.PerformLongTask();
// once the long task is completed then it continues and you can use the result
UI.Item.Label = result;
Чтобы привести реальный пример, вот некоторый код написанного мной FTP-клиента, который имеет фронт WPFконец.Когда нажата кнопка запуска, передача ftp запускается в ее собственной задаче, затем в задаче запускается цикл while, который обновляет интерфейс каждые полсекунды, так что ни один из них не мешает потоку интерфейса.Опять тот же код, только что завернутый в код лямбады.
private void btnStart_Click(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(() =>
ftp.Mirror(@"C:\LocalFolder", "/RemoteFolder", 10));
Task.Factory.StartNew(() =>
{
while (true)
{
lbPercentSuccess.Dispatcher.Invoke(new Action(() =>
{
lbPercentSuccess.Content = ftp.FtpProgress.SuccessPercentage;
lbPercentError.Content = ftp.FtpProgress.ErrorPercentage;
lbPercentTotal.Content = ftp.FtpProgress.TotalPercentage;
lbDuration.Content = ftp.FtpProgress.Duration;
}));
Thread.Sleep(500);
}
});
}