2016-02-03 1 views
0

У меня есть длинная операция, которая создает некоторые инструменты в основном пользовательском интерфейсе.Длительные операции в основной нити вынуждают пользовательский интерфейс зависать

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

Мой код выглядит следующим образом:

Sub DoWork() 
    DoLongOperation() 
End sub 

sub DoLongOperation() 
For K as integer = 0 to 50 
    'Here I create tools and add them to a StackPanel in the window 
    'While doing this I update a progressBar value 
    ProgressBar1.value=Some value 
Next 
End sub 

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

+0

Вы должны использовать 'IProgress' с' await'. Подробнее см. Здесь [здесь] (http://blog.stephencleary.com/2012/02/reporting-progress-from-async-tasks.html). –

+0

http://stackoverflow.com/a/18033198/2882256 –

+0

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

ответ

0

Я получил его. Я разделил свой юнит на 50 частей. В конце создания одного инструмента я могу установить индикатор выполнения. После этого я могу создать вторую. и продолжайте.

0

Причина, по которой ProgressBar не обновляется, заключается в том, что вы по-прежнему блокируете основной поток. Ваша длинная операция должна быть вызвана в дополнительном потоке. Таким образом, вы можете использовать, например, метод Task.Run. Еще одна вещь, которую нужно помнить, в дополнительном потоке вы не можете изменить какой-либо пользовательский интерфейс, чтобы сделать это, например, для свойства Dispatcher вашего окна.

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    Task.Run(() => 
    { 
     for(int i = 0; i < 50; i++) 
     { 
      Thread.Sleep(1000); // some long operation 

      var progress = i*2; 

      Dispatcher.Invoke(() => 
      { 
       progressBar1.Value = progress; 
      }); 
     } 
    }); 
} 
+0

Можете ли вы привести мне пример, пожалуйста. –

+0

да, но только в C# :) –

0

Как было сказано ранее, для обновления пользовательского интерфейса, или все-таки сделать это разблокировано и использовать при этом очень долго операциях вы должны сделать эту операцию в другом потоке. Вы можете использовать BackgroundWorker для этого. Если вы не хотите создавать новые методы только для нового потока вы можете делегировать их, так что вы можете сделать что-то вроде этого:

Imports System.ComponentModel 
Sub DoLongOperation() 
    Dim bgWorker As New System.ComponentModel.BackgroundWorker() 
    bgWorker.WorkerReportsProgress = True 

    AddHandler bgWorker.DoWork, 
     Sub(sender, args) 
      For K as integer = 0 to 50 
       'Here I create tools and add them to a StackPanel in the window 
       'While doing this I update a progressBar value 

       bgWorker.ReportProgress(123) 
      Next 
     End Sub 

    AddHandler bgWorker.ProgressChanged, 
     Sub(sender, args) 
      ProgressBar.Value = args.ProgressPercentage 
     End Sub 

    AddHandler bgWorker.RunWorkerCompleted, 
     Sub(sender, args) 

     End Sub 

End sub 

Поскольку вы не можете добавлять/удалять или делать другие вещи из другого потока на StackPanel, вы можете поместить элемент, который вы хотите добавить в метод bgWorker.ReportProgress(), а затем обновить его из .ProgressChanged события, так что будет так:

AddHandler bgWorker.DoWork, 
    Sub(sender, args) 
     For K as integer = 0 to 50 
      'Here I create tools and add them to a StackPanel in the window 
      'While doing this I update a progressBar value 

      Dim item As Object 'stackpanel's item that you want to add later on. Can be any type 

      bgWorker.ReportProgress(123, item) 
     Next 
    End Sub 

AddHandler bgWorker.ProgressChanged, 
    Sub(sender, args) 
     ProgressBar.Value = args.ProgressPercentage 
     StackPanel.Chlidren.Add(args.UserState) 
    End Sub 
+0

Отлично. Я понял это. Я не проверял его до сих пор. Но, я буду как можно скорее. Благодарю. –

+0

У меня есть эта ошибка: «Вызывающий поток должен быть STA, потому что для этого требуется множество компонентов пользовательского интерфейса». Я сделал операцию создания в отдельном подразделении и пометил ее _ и не работал. –

+0

Вы можете попытаться вызвать метод 'Application.Current.Dispatcher.Invoke ((Action) delegate {}' или создать новый 'Thread' –

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

  • Нет связанных вопросов^_^