2015-11-30 3 views
0

У меня есть следующая проблема. У меня синхронное действие .Save(), которое длится довольно много минут. Я не могу сделать это async (сторонняя библиотека), поэтому, чтобы поддерживать пользовательский интерфейс, я использую его все в Task.Run().while цикл во время ожидания для задачи async

Я хотел бы сообщить о прогрессе, так что пользователь видит, что что-то происходит - и я хочу, чтобы сделать его в ярлыке Status - простой и старой школы добавлять и удалять точки в строку, вроде как
Подождите.
Wait ..
Подождите ...
Подождите.

Я не знаю, как это сделать простым способом - я думал о цикле while, который прерывался бы после завершения задачи, но, похоже, не работает - либо пользовательский интерфейс заблокирован, либо статус метка не обновляется.

Я попробовал несколько вещей, например:

bool done = false; 
      Task.Run(() => 
      { 
       Exporter.DoLongSyncTask(); 
      }).ContinueWith(r => done = true); 
      StatusLabel = "."; 
      while (!done) 
      { 
       if (StatusLabel == "") 
        StatusLabel = "."; 
       else if (StatusLabel == ".") 
        StatusLabel = ".."; 
       else if (StatusLabel == "..") 
        StatusLabel = ""; 
      } 

(StatusLabel является свойством с INotifyPropertyChanged реализовано, она работает нормально)

и более сложного

private async Task<bool> DoTheWork() 
     { 

      await Task.Run(() => TheFile.Save()); 
      return true; 
     } 

      private string ReportProgress(string status) 
     { 
      if (status == ".") 
       status = ".."; 
      else if (status == "..") 
       status = "..."; 
      else if (status == "...") 
       status = "."; 
      MyProgress.Report(new InDesignExporterProgress { StatusInfo = status }); 
      return status; 
     } 

private string ReportProgress(string status) 
{ 
    if (status == ".") 
     status = ".."; 
    else if (status == "..") 
     status = "..."; 
    else if (status == "...") 
     status = "."; 
    MyProgress.Report(new SomeProgressClass { StatusInfo = status }); 
    return status; 
}  

а выше, вызываются отсюда

 bool done = false; 
     Task.Run(() => 
     { 
      done = DoTheWork().Result; 
     }); 
     string status = "."; 
     while (!done) 
     { 
      status = ReportProgress(status); 
     } 

Итак, каков правильный путь?

+0

Lets попробовать вторую попытку на этот вопрос, как я полагаю, никто не будет смотреть на свежий вопрос с -3 голосов в любом случае. Надеюсь, что все downvoters теперь будут делать что-то более конструктивное :) – Bartosz

+3

Вам нужно указать время потока пользовательского интерфейса, чтобы выполнить его пересылку сообщений. Если вы не можете изменить исходный метод для отчета о прогрессе, одним из вариантов является периодическое обновление состояния на основе таймера. –

+0

Переменная 'done', которую вы можете использовать для сигнализации двух потоков, может не работать, потому что некоторое значение времени не доступно для другого потока. –

ответ

0

Чтобы знать, если задача была завершена, проверьте значение свойства.

while (!task.IsCompleted) 
{ 
    // ... 
} 

Но, за то, что я думаю, что вы пытаетесь, я бы что-то вроде этого:

using (var timer = new System.Windows.Forms.Timer()) 
{ 
    timer.Tick += (s, e) => 
    { 
     if (StatusLabel == "") 
      StatusLabel = "."; 
     else if (StatusLabel == ".") 
      StatusLabel = ".."; 
     else if (StatusLabel == "..") 
      StatusLabel = ""; 
    }; 
    timer.Interval = 100; 
    timer.Enabled = true; 

    await Task.Run(() => Exporter.DoLongSyncTask); 
} 
0

Я думаю, что вы блокируете поток пользовательского интерфейса с циклом while, так как я предполагаю, что он работает на этом потоке.

Я предлагаю вам попробовать изменить время цикла, как это и подпись метода для асинхронной задачи

public async Task DoSomething(){ 
     bool done = false; 
     Task.Run(() => 
     { 
      Exporter.DoLongSyncTask(); 
     }).ContinueWith(r => done = true); 

     StatusLabel = "."; 
     while (!done) 
     { 
      if (StatusLabel == "") 
       StatusLabel = "."; 
      else if (StatusLabel == ".") 
       StatusLabel = ".."; 
      else if (StatusLabel == "..") 
       StatusLabel = ""; 
      await Task.Delay(200); 
     } 
} 
+7

' while (! Done) {..... await Task.Delay (200); } 'никогда не является хорошим кодированием .... – Eser

+3

@Eser, не могли бы вы объяснить? что было бы лучше в этом случае? –

Смежные вопросы