Ваше приложение хочет повторно отправлять обновления из фонового потока в пользовательский интерфейс. Для этого есть встроенный механизм: событие ProgressChanged
для рабочего фона. A ReportProgress
вызов запускается в фоновом режиме, но выполняется в потоке пользовательского интерфейса.
I изменение один вещь, однако. Производительность может ухудшиться при слишком большом количестве вызовов с перекрестными потоками. Таким образом, вместо того, чтобы посылать обновления каждую итерацию, я вместо этого будет партия их в 100.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
const int maxIterations = 10000;
var progressLimit = 100;
var staging = new List<int>();
for (int i = 0; i < maxIterations; i++)
{
staging.Add(i);
if (staging.Count % progressLimit == 0)
{
// Only send a COPY of the staging list because we
// may continue to modify staging inside this loop.
// There are many ways to do this. Below is just one way.
backgroundWorker1.ReportProgress(staging.Count, staging.ToArray());
staging.Clear();
}
}
// Flush last bit in staging.
if (staging.Count > 0)
{
// We are done with staging here so we can pass it as is.
backgroundWorker1.ReportProgress(staging.Count, staging);
}
}
// The ProgressChanged event is triggered in the background thread
// but actually executes in the UI thread.
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage == 0) return;
// We don't care if an array or a list was passed.
var updatedIndices = e.UserState as IEnumerable<int>;
var sb = new StringBuilder();
foreach (var index in updatedIndices)
{
sb.Append(index.ToString() + Environment.NewLine);
}
textBoxOutput.Text += sb.ToString();
}
EDIT:
Для этого необходимо установить WorkerReportsProgress
свойство фон работника к истине.
Не важно, чтобы вы проходили подсчет с помощью вызова ReportProgress. Я делаю это просто, чтобы иметь что-то и быстро проверить, могу ли я вернуться.
Следует помнить о том, сколько событий вызывается и ставится в очередь. У вашего оригинального приложения было 10 000 вызовов перекрестных потоков и 10 000 измененных текстовых событий для textBoxOutput
. В моем примере используется 100 вызовов с перекрестными потоками, так как я использую размер страницы 100. Я мог бы сгенерировать 10 000 измененных текстовых событий для текстового поля, но вместо этого использовать объект StringBuilder для хранения полной страницы изменений и затем обновлять текстовое поле один раз для этого стр. Таким образом, текстовое поле содержит только 100 событий обновления.
EDIT 2
ли не нуждается ваше приложение подкачки не главная проблема. Самый большой урон должен заключаться в том, что фоновой работник действительно должен использовать ReportProgress
при попытке передать информацию обратно в пользовательский интерфейс. См. Это MSDN Link. Особо следует отметить следующее:
Вы должны быть осторожны, чтобы не манипулировать каких-либо объектов пользовательского интерфейса в обработчика событий DoWork. Вместо этого обменивайтесь с пользовательским интерфейсом событиями ProgressChanged и RunWorkerCompleted.
Не удивительно, у вас есть цикл, который делает работу внутри Invoke (который вызывается на потоке пользовательского интерфейса) – Icepickle
Единственное ваш фон работник делает отправка весь цикл в потоке пользовательского интерфейса выполнить его там. –
'textBoxOutput.Invoke' будет выполнять делегат синхронно в потоке пользовательского интерфейса и, таким образом, блокирует его. Непонятно, чего вы пытаетесь достичь, но, по-видимому, вам вообще не нужен «BackgroundWorker». –