C # .NET async / await сообщает о прогрессе, не передавая IProgress везде? - PullRequest
0 голосов
/ 16 ноября 2018

Позвольте мне предвосхитить это, сказав, что я совершенно новичок в 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);
}

1 Ответ

0 голосов
/ 16 ноября 2018

Здесь «свойство прогресса» для создания отчетов с событиями PropertyChanged.

Это исправит проблему с зависимостью IProgress

, не пропуская IProgress везде

public sealed class PropertyProgress<T> : IProgress<T>, INotifyPropertyChanged
{
      public PropertyProgress(T initialProgress = default(T));

      public T Progress { get; }

      public event PropertyChangedEventHandler PropertyChanged;
}
...