Я согласен с другими, что код станет чище, если вы замените BackgroundWorker
на Task.Run
. Между прочим, гораздо проще сочинять с await
(под «сочинять» я подразумеваю «сделай это; потом сделай это»). Обратите внимание, что вы должны использовать await
вместо ContinueWith
.
Таким образом, ваш исходный код будет выглядеть примерно так, как только BGW преобразуется в Task.Run
:
public string GenerateSomeText(CancellationToken token)
{
// Generate some text
}
public async Task GenerateAsync()
{
var cts = new CancellationTokenSource();
var result = await Task.Run(() => GenerateSomeText(cts.Token));
await DisplayAsync(result);
}
Итак, что касается вопроса, который вызвал этот вопрос, во-первых: как выполнять большую часть пользовательского интерфейса, не блокируя его? Ну, нет хорошего решения, потому что работа - Работа интерфейса . Так что это не может быть помещено в фоновый поток. Если у вас есть тонны работы пользовательского интерфейса, единственные реальные варианты:
- Виртуализируйте ваши данные . Таким образом, вам нужно только обработать количество отображаемого пользовательского интерфейса. Это лучшее решение этой проблемы.
- Если вы не хотите вносить вклад в виртуализацию своих данных, вы можете использовать хак, где ваш код периодически приостанавливает работу пользовательского интерфейса, чтобы пользовательский интерфейс остается отзывчивым.
Я не верю, что WPF RichTextBox
поддерживает виртуализацию, поэтому для этого вам может потребоваться go сторонняя организация. Если вы хотите взломать паузу, вы можете сделать что-то вроде этого:
public async Task<int> DisplayAsync(string text)
{
int count = 0;
// Write text
Paragraph paragraph = new Paragraph();
richTextBox1.Document = new FlowDocument(paragraph);
richTextBox1.BeginChange();
paragraph.Inlines.Add(new Run(text));
richTextBox1.EndChange();
// Colorize Text here...
// Is a loop that takes some time.
for (loop)
{
... // Colorize piece of text.
await Task.Delay(TimeSpan.FromMilliseconds(20));
}
return count;
}