Раньше я часто использовал Invoke для решения подобных проблем, и проблем никогда не было. Но слышал, что с появлением async/await эта проблема решена. В частности, натыкаюсь на такие ответы, где автор первого ответа пишет, что для решения, начиная с .NET 4.0 можно "Использовать Асинхронную модель на основе задач (TAP) и ключевые слова async-await".
Сейчас я использую .NET Framework 4.5.2 и VS2015, и пытаюсь следовать его совету:
private async void startButton_Click(object sender, EventArgs e){
await Task.Run(() => Scope_Save(sourceText.Text, folderPath, statusView, ref flag));
}
void Scope_Save(string source, string path, RichTextBox logText, ref bool? _flag)
{
logText.Text += Environment.NewLine + "Читаем построчно:";
}
Здесь sourceText и statusView - это RichTextBox-ы. В принципе от первого легко избавиться на обычный текст, но не суть. При первом обращении к logText, я получаю ошибку из сабжа. Что я делаю не так?
async/await
не решают проблемы доступа к контролам из другого потока (т.к. WinForms строго это проверяет). Поэтому и доступ в Task.Run
не возможет.
Но async/await
значительно упрощает написание кода, который работает в разных потоках. Скорее всего проще всего это будет понять из примера из другого ответа.
private async void button1_Click(object sender, EventArgs e)
{
// тут вы статруете таск и он запускается в отдельном потоке
// с помощью await вы дожидаетесь результата
// но работы с UI в отдельном потоке нет, т.к. как и раньше будут бросаться исключения
string result = await Task.Factory.StartNew<string>(
() => Worker.SomeLongOperation(),
TaskCreationOptions.LongRunning);
// этот код выполняется только после завершения потока, за что и отвечает await
// но для WinForms тут есть ещё один важный момент, это то, что этот код будет выполняться в UI потоке, т.е. уже никаких исключений не будет
// это все делается при помощи async/await и SynchronizationContext, статей в интернете достаточно, если интересно почитайте.
this.label1.Text = result;
}
И сравните его с вашим примером, в котором вы напрямую пытаетесь получить доступ из отдельного потока, поэтому и исключение. async/await
не прямая замена Invoke.
В вашем коде вы не пытаетесь следовать советам, вы пытаетесь получить доступ к контролу НЕ из UI потока, что делать нельзя.
// если весь метод вызывается из UI потока, то
private async void startButton_Click(object sender, EventArgs e){
// тут можно работать с UI элементами
await Task.Run(() => // тут НЕЛЬЗЯ работать с UI элементами т.к. это не UI поток);
// тут можно работать с UI элементами
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Добрый день дамы и господа) набросал тут вот такой код: