#c# #wpf #multithreading #task
#c# #wpf #многопоточность #задача
Вопрос:
Я написал этот код:
public double SumRootN(int root)
{
double result = 0;
for (int i = 1; i < 10000000; i )
{
tokenSource.Token.ThrowIfCancellationRequested();
result = Math.Exp(Math.Log(i) / root);
}
return resu<
}
private void btnclick_Click(object sender, RoutedEventArgs e)
{
tokenSource = new CancellationTokenSource();
txttest.Text = "";
var watch = Stopwatch.StartNew();
List<Task> tasks = new List<Task>();
var ui = TaskScheduler.FromCurrentSynchronizationContext();
for (int i = 2; i < 20; i )
{
int j = i;
var compute = Task.Factory.StartNew(() =>
{
return SumRootN(j);
}, tokenSource.Token);
tasks.Add(compute);
var displayResults = compute.ContinueWith(
resultTask =>
txttest.Text
= "root " j.ToString() " "
compute.Result.ToString()
Environment.NewLine,
CancellationToken.None,
TaskContinuationOptions.OnlyOnRanToCompletion,
ui);
}
}
Это работает в WPF, но когда я написал этот код таким образом;
tokenSource = new CancellationTokenSource();
var watch = Stopwatch.StartNew();
List<Task> tasks = new List<Task>();
var ui = TaskScheduler.FromCurrentSynchronizationContext();
Report
= ((Microsoft.Office.Interop.Excel.Range)_sheet.Cells[row, "B"]).Value2;
var compute = Task.Factory.StartNew(() =>
{
return Report;
}, tokenSource.Token);
tasks.Add(compute);
var displayResults
= compute.ContinueWith(resultTask =>
txtReport.Text
= compute.Result.ToString()
Environment.NewLine,
CancellationToken.None,
TaskContinuationOptions.OnlyOnRanToCompletion,
ui);
Он не работает, хотя txtReport.Text
имеет правильные значения, но он не отображается в середине операции, но когда операция заканчивается txtReport
, отображаются ее значения
Почему этот код не работает?
Комментарии:
1. Реализует ли ваша модель представления
INotifyPropertyChanged
интерфейс?2. Вам все равно нужно сообщить XAML, что свойство изменилось.
3. пожалуйста, опишите меня немного подробнее…
4. @ChrisF: я не вижу здесь отсутствующего INPC. OP устанавливает txttest. Текст напрямую. Нет необходимости в PropertyChanged-событии. Я ошибаюсь?
5. @HCL — Ah — я понимаю вашу точку зрения. Мои комментарии выше неверны — я неправильно понял, какое свойство обновлялось.
Ответ №1:
ContinueWith
создает продолжение, которое выполняется асинхронно при завершении целевой задачи. Т.е. он обновит результат только SumRootN
после завершения вашей операции.
Ответ №2:
Я никогда не работал с TaskScheduler, поэтому я не могу дать вам прямой отзыв, что не так. Но из описания вашей проблемы я совершенно уверен, что проблема в том, что пользовательский интерфейс заблокирован. Пока ваш код не завершен, пользовательский интерфейс обновляться не будет.
Для выполнения трудоемких операций выполняйте их с помощью BackgroundWorker. Однако позаботьтесь о том, чтобы вы не могли напрямую устанавливать значения своих элементов управления из асинхронного. Либо используйте диспетчер для маршрутизации вашей команды в UI-thread, либо используйте ProgressChanged-event.
Следующий код показывает, как использовать BackgroundWorker:
BackgroundWorker bgWorker = new BackgroundWorker() { WorkerReportsProgress=true};
bgWorker.DoWork = (s, e) => {
// Do here your calculations
// Use bgWorker.ReportProgress(); to report the current progress
};
bgWorker.ProgressChanged =(s,e)=>{
// Here you will be informed about progress and here it is save to set the labels value.
};
bgWorker.RunWorkerCompleted = (s, e) => {
// Here you will be informed if the job is done.
};
bgWorker.RunWorkerAsync();
Комментарии:
1. но я использую подобный код в winforms, и он работает. используйте 1’var ui = TaskScheduler. FromCurrentSynchronizationContext(); ‘ для синхронизации потоков. почему это не работает?
Ответ №3:
Для этого есть несколько советов по устранению неполадок… Возможно, вам придется сначала ответить на эти вопросы…
- Где на самом деле находится ваш код? В вызове Button_click()?
- Когда вы ставите brekapoint в свой код
TaskScheduler.FromCurrentSynchronizationContext();
, какойSynchronizationContext
объект вы видите?Dispatcher
тип? Или какой-то другой тип? - Есть ли конкретная причина для использования TPL? Не можете ли вы использовать
BackgroundWorker
иDispatcher
сопрягать?