Позвольте мне предвосхитить это, сказав, что я совершенно новичок в C # - я родом из Java, где я не очень много работал с GUI.
Я создал элементарное приложение Winforms, у которого есть пара кнопок, которые запускают некоторые длительные задачи, где сами эти задачи могут иметь или не иметь ряд подзадач с неопределенным временем выполнения. Эти подзадачи включают вызовы API, загрузку файлов и сопоставление объектов из данных файла.
В основной форме есть одна метка, которая ранее обновлялась путем прямого доступа к ней из любой выполняемой в данный момент функции, например,
labelProgress.Text = "Beginning main long running function";
myClient.LongRunningFunction(); //more methods called inside this function, which update the label directly
labelProgress.Text = "Long running function is complete";
Очевидно, что проблема в том, что графический интерфейс заблокирован (невозможно нажать кнопку X или переместить окно). Я знаю, что это не «правильный» метод для долго выполняющихся функций для обновления графического интерфейса.
Итак, теперь приступим к решению проблемы, и корень моего вопроса - Как мне сообщить о прогрессе, чтобы обновить мою метку, из нескольких вложенных вызовов методов, не пропуская IProgress везде? Все из примеров, которые я только что прочитал, глубиной один - я имею в виду, что обработчик запускает задачу, и эта задача затем сообщает о прогрессе напрямую, без передачи другим методам, которые сами также должны сообщать о прогрессе.
Я просто хочу постоянно обновлять метку значимой информацией о состоянии, чтобы видеть, что происходит, но, похоже, единственный способ сделать это - передавать IProgress вниз и вниз в каждом вызове метода. Есть ли лучший способ сделать это?
Это мой обработчик событий кнопки верхнего уровня
private async void buttonStart_Click(object sender, EventArgs e)
{
MyClient client = new MyClient();
var progress = new Progress<String>(s => labelProgress.Text = s);
await Task.Factory.StartNew(() => myClient.LongRunningFunction(progress), TaskCreationOptions.LongRunning);
}
Тогда внутри класса MyClient
public async Task LongRunningFunction(IProgress<String> progress)
{
await apiGetter.getFiles(); //async call to download some files, might want to report progress inside here later too
progress.Report("Processing downloaded files");
fileProcessor.processFiles(progress); //pass the IProgress here too?
}
И, наконец, FileProcessor
public void processFiles(IProgress<String> progress)
{
//collect filenames from a predetermined location, churn through
progress.Report("Working on file " + filename);
doSomeStuffWithFileAndAlsoReportOnProgress(filename, progress); //again passing the IProgress down a level
progress.Report("Done with " + filename);
}