2014-12-26 3 views
0

Я застрял в проблеме, когда я использую Backgroundworker, чтобы показать ход моей работы в индикаторе выполнения. Код, используемый для BackgroundWorker: -Как использовать progressbar, backgroundworker, windows form вместе в C#?

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
    { 
     Thread.Sleep(200); 
     for (int i = 0; i <= 100; i++) 
     { 
      Delegate del= new DELEGATE(simulateHeavyWork); 
      this.Invoke(del); 

      backgroundWorker1.ReportProgress(i); 
      if (backgroundWorker1.CancellationPending) 
      { 
       e.Cancel = true; 
       backgroundWorker1.ReportProgress(0); 
       return; 
      } 
     } 

    } 

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     progressBar1.Value = e.ProgressPercentage; 
     percentLabel.Text = e.ProgressPercentage.ToString() + "%"; 

    } 

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     if (e.Cancelled) 
     { 
      MessageBox.Show("Cancelled"); 
     } 
     else 
     { 
      MessageBox.Show("Completed"); 
     } 
    } 

Я создал делегат по коду: -

public partial class Form1 : Form 
{ 
    private delegate void DELEGATE(); 


    public Form1() 
    { 
     InitializeComponent(); 

    } 
    private void simulateHeavyWork() 
    { 
     Thread.Sleep(100); 

     ...lines of code to perform some search logs operation.. 
.... 
     } 
} 

Функциональность Я хочу добиться того, что прогресс бар должен сообщить о достигнутом прогрессе моей функции simulateHeavyWork() который фактически использует поток пользовательского интерфейса, так как он должен принимать данные от моих элементов управления формой и обновлять их.

Теперь проблема заключается в том, что: - a) код на самом деле вызывает simulateHeavyWork() и дает выходные данные, которые обновляют элементы управления ui и выполняются работы. (Примечание: я использовал делегат здесь, чтобы избежать ошибки. элементы управления, работающие на нити ui, поскольку моей функции необходимо использовать элементы управления пользовательским интерфейсом.)

Как только это будет сделано, он начнет обновлять индикатор выполнения, а это неправильно и выглядит так, как будто он вызывает симуляциюHeavyWork снова и снова с разрывом сна (100) ,

Пожалуйста, помогите !!! С уважением

+0

Очень странный подход. Фоновые потоки, как правило, необходимы для предотвращения замораживания UI при длительных операциях. Так что бегущий фоновый поток и сразу вызывающий его делегат для запуска в потоке пользовательского интерфейса (и его замораживание) выглядит странно для меня. –

+0

yep, но я не мог найти другого простого способа сделать это, я хочу показать индикатор выполнения и позволить пользователю отменить операцию. Проблема в том, что работа с длительным сроком действия на самом деле использует элементы управления ui, такие как кнопка формы, где пользователь вводит данные, такие как id, описание даты и т. Д., И запрашивает подсчет этого числа в журналах, которые должны снова отображаться в форме. – user3222101

+0

Ну, может быть, будет лучше разделить вашу логику - таким образом, оставить в фоновом режиме долговременные вычисления и обновить элементы пользовательского интерфейса в обработчике 'ProgressChanged'? –

ответ

1

user3222101, как указано Энди раньше, вы работаете simulateHeavyWork() непрерывно. Более того, вызывая Invoke, вы запускаете этот метод в потоке пользовательского интерфейса, который вызывает дополнительный сон в потоке пользовательского интерфейса. В основном Invoke использует контур сообщения (насос) используемого вами элемента управления (Form1 в этом случае) и помещает ваш делегат в очередь потока пользовательского интерфейса для выполнения. Я думаю, что это не очень хорошая практика из-за вызова Sleep() и длительных операций журнала в вашем методе simulateHeavyWork().

Надеюсь, четко разобраться в вашей проблеме. Что я предлагаю - это разделение трудоемких операций журнала с потоком пользовательского интерфейса. Не тратьте драгоценное время на поток пользовательского интерфейса с медленными и скучными операциями ввода-вывода. Получите значения из элементов управления (используя Invoke в BackgroundWorker, как я объясню ниже), сделайте все, что хотите, в BackgroundWorker и обновите свой графический интерфейс (снова используя Invoke), не касаясь потока пользовательского интерфейса для таких тяжелых задач.

Как предложил Энди, вы можете передавать данные через параметр RunWorkerAsync, и вы должны создать класс, который может хранить любые данные, которые вам нужны (поскольку он принимает только один параметр). Тем не менее, вы можете получать значения из своей Формы, когда вам нужно из другого потока, используя Invoke. Invoke метод также возвращает значение из вашего делегата (см. Пример по ссылке ниже), и это дает вам возможность получить значения ваших элементов управления в форме. Создайте делегат, который возвращает объект класса типа, который вы скрепили для RunWorkerAsync, и используйте эти значения в потоке BackgroundWorker. Пожалуйста, посмотрите на пример в here.

public static string GetTextThreadSafe(this TextBox box) 
{ 
    return GetTextBoxText(box); 
} 

Кроме того, пример использует Func<...>, чтобы вернуть значение.

Таким образом, вы можете спать (в BackgroundWorker потоке) некоторое время, а затем получать значения из ваших элементов управления (текущие значения) и делать все, что хотите (снова в строке BackgroundWorker). Я думаю, это улучшает ваш код.

+0

Спасибо Deniz :-) – user3222101

0

С вашего вопроса: ", что не так и выглядит так, как будто он вызывает симуляциюHeavyWork снова и снова с промежутком сна (100)."

Конечно, он звонит. Просто посмотрите на ваш код:

for (int i = 0; i <= 100; i++) 
{ 
    Delegate del= new DELEGATE(simulateHeavyWork); 
    this.Invoke(del); 

Так вы звоните simulateHeavyWork 100 раз здесь. А так как вы набрали Thread.Sleep(100); в теле simulateHeavyWork - разрыв между звонками о Sleep(100)

+0

да .. любой способ, если вы можете предложить достичь этого, было бы здорово? – user3222101

+0

@ user3222101 Я думаю, что вы не должны использовать делегирование в потоке пользовательского интерфейса и выполнять всю свою работу в '_DoWork'. Затем определите свой текущий прогресс (способ его выполнения зависит от конкретной задачи. Если это какой-то поиск в журнале, как указано в вашем коде, - возможно, это отношение текущего номера строки журнала и общего количества строк) и на основе изменение этого хода выполнения [ReportProgress] (http://msdn.microsoft.com/en-us/library/a3zbdb1t%28v=vs.110%29.aspx) метод переопределяет принятие объекта objectState, где вы можете передать все, что угодно нужен обработчик 'ProgressChanged'. –

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