2015-10-26 4 views
0

У меня есть приложение vb.net, обрабатывающее большой объем данных. Из-за требований к памяти процесса я делаю это порционно, с общей планировочной структурой следующим образом:Обновление пользовательского интерфейса при ожидании завершения задач

Do while Start < TotalNumberOfObjects 

    [cache data used for the upcoming batch] 

    For i = Start to Stop 

     [process data using multiple tasks...for example:] 
     t=taskfactory.startnew(doStuff(i)) 
     TaskList.TryAdd(t.ContinueWith(Sub()          
             Me.BeginInvoke(DelegateUpdateProgress, {progress}) 
             End Sub)) 
    Next 

    [Wait for tasks to complete... 
    Normally I would wait for the tasks using task.waitall(), 
    but this will cause the UI to wait to update until all tasks are complete] 

    Start = Stop+1 
    Stop = Stop+Increment 

    [clear data from batch that was just completed] 

loop 

Что правильный способ:

  1. Wait для всех задач, чтобы завершить перед переходом к следующей партии?
  2. Обновление пользовательского интерфейса с общим ходом по мере выполнения каждой задачи?

My target framework - .NET 4.0.

Я ценю любой вход.

EDIT: В настоящее время я обновление пользовательского интерфейса после завершения каждой задачи с помощью task.continuewith() и вызова me.beginInvoke обновить форму,

TaskList.TryAdd(t.ContinueWith(Sub()          
           Me.BeginInvoke(DelegateUpdateProgress, {progress}) 
           End Sub)) 

Однако, это несовместимо с тем, как я ожидал бы ждать списка задачи для завершения, task.waitall(tasklist), потому что вызов task.waitall заставит поток пользовательского интерфейса ждать обновления до тех пор, пока все задачи не будут завершены.

+0

@The_Black_Smurf Не рекомендую 'Application. DoEvents' (в SO есть немало сообщений, объясняющих, почему это плохая идея). Это типичная проблема, которая должна решаться при многопоточности. Если вы хотите сохранить его простым и заинтересовать только два потока (GUI + все вычисления), вы можете положиться на «BackgrounWorker». – varocarbas

+0

Работает на нескольких потоках (GUI + Calculations + Database operations), поэтому я создаю много задач и жду их завершения. – DrCocoa

+0

Тогда я не уверен, понимаю ли я вашу проблему. Если у вас разные потоки, графический интерфейс, безусловно, обновляется (он не застывает). Вы спрашиваете, в какой момент вам следует отображать новую информацию для пользователя?В конце или в промежутке? Очень сложно рассказать с информацией, которую вы предоставляете (= нет); Я думаю, что это вопрос личного вкуса (и зависит от конкретной ситуации, о которой вы говорите). Помните, что SO - это конкретные проблемы, связанные с конкретными проблемами программирования (например, как я могу избежать того, чтобы мой графический интерфейс застыл?), не обсуждать абстрактные рекомендации. – varocarbas

ответ

0

Почему вы не ставите свою рутину в структуру Backgroundworker?

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

При необходимости вы также можете обновить пользовательский интерфейс от Backgroundworker, но для этого вам потребуются особые требования.

Вы можете свериться здесь: https://msdn.microsoft.com/en-us//library/ywkkz4s1.aspx

+0

Пожалуйста, не связывайтесь с внешними ресурсами, если вы также не включите данные со связанной страницы в свой ответ. Кроме того, вы связались с документом на португальском языке. – Enigmativity

+0

Ops! Моя вина ... Спасибо, что предупредил меня. Но любопытно, что страница появляется здесь уже на английском языке, как и раньше. В любом случае, я отредактирую ссылку в ответе. –

0

Прежде всего, необходимо создать делегат, а затем использовать Dispatcher.Invoke

В приведенном ниже примере, кнопка изменяется с поддержкой отключить (или другой наоборот):

Delegate Sub SetRecordButtonEnabledCallback(ByVal Enabled As Boolean) 
    Friend Sub SetRecordButtonEnabled(ByVal Enabled As Boolean) 
     Me.btnDGRecord.IsEnabled = Enabled 
    End Sub 

после этого все, что вам нужно сделать, это вызвать следующий код из вашего таймера, чтобы вызвать его:

Dim DesiredValue, как Boolean = True

Me.Dispatcher.Invoke (Новый SetRecordButtonEnabledCallback (AddressOf SetRecordButtonEnabled), New Object() {} DesiredValue)

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