C# Winform ProgressBar и BackgroundWorker
у меня следующая проблема:
у меня есть форма с именем MainForm. Мне предстоит долгая операция над этим бланком.
в то время как эта длинная операция продолжается, мне нужно показать другую из названной ProgressForm поверх MainForm.
ProgressForm содержит индикатор выполнения, который необходимо обновить во время длительной операции.
после того как длинная деятельность завершена, ProgressForm должно быть закрыто автоматически.
Я написал следующий код:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace ClassLibrary
{
public class MyClass
{
public static string LongOperation()
{
Thread.Sleep(new TimeSpan(0,0,30));
return "HelloWorld";
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace BackgroungWorker__HelloWorld
{
public partial class ProgressForm : Form
{
public ProgressForm()
{
InitializeComponent();
}
public ProgressBar ProgressBar
{
get { return this.progressBar1; }
set { this.progressBar1 = value; }
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using ClassLibrary;
namespace BackgroungWorker__HelloWorld
{
public partial class MainForm : Form
{
ProgressForm f = new ProgressForm();
public MainForm()
{
InitializeComponent();
}
int count = 0;
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (f != null)
{
f.ProgressBar.Value = e.ProgressPercentage;
}
++count;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
MessageBox.Show("The task has been cancelled");
}
else if (e.Error != null)
{
MessageBox.Show("Error. Details: " + (e.Error as Exception).ToString());
}
else
{
MessageBox.Show("The task has been completed. Results: " + e.Result.ToString());
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
if (f == null)
{
f = new ProgressForm();
}
f.ShowDialog();
//backgroundWorker1.ReportProgress(100);
MyClass.LongOperation();
f.Close();
}
private void btnStart_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void btnCancel_Click(object sender, EventArgs e)
{
backgroundWorker1.CancelAsync();
this.Close();
}
}
}
Я не могу найти способ, чтобы обновить progressBar
.
где я должен разместить backgroundWorker1.ReportProgress()
и как мне это назвать?
Я не должен вносить никаких изменений в MyClass
потому что я не знаю, что произойдет или сколько времени потребуется для завершения операции на этом уровне моего приложения.
кто-нибудь может мне помочь?
4 ответов
одна проблема заключается в том, что вы спите в течение 30 секунд. Как правило, вы бы назвали ReportProgress
в различных точках в течение длительных задач. Чтобы продемонстрировать это, вы можете изменить свой код на сон в течение 1 секунды, но 30 раз-вызов ReportProgress
каждый раз, когда он заканчивает спать.
другая проблема заключается в том, что ты показываешь свой ProgressForm
С фоновый поток. Вы должны начать его в UI нить, но зацепить фоновый рабочий ProgressChanged
событие к нему. Затем, когда фоновый работник сообщает о ходе выполнения, форма выполнения будет обновлена.
ReportProgress-это метод, который вам нужно будет вызвать в своем "рабочем" методе. Этот метод вызовет событие ProgressChanged.
в вашей форме вы можете прикрепить eventhandler к событию ProgressChanged. Внутри этого eventhandler вы можете изменить положение progressbar. Можно также присоединить eventhandler к событию RunWorkerCompleted, и внутри этого eventhandler можно закрыть форму, содержащую progressbar.
следует отметить, что вам нужно установить
backgroundWorker1.WorkerReportsProgress = true;
Если вы хотите, чтобы фоновый работник поднял событие ProgressChanged и
backgroundWorker1.WorkerSupportsCancellation = true;
Если вы хотите иметь возможность отменить рабочий поток.
Как сказали другие, запустите f.ShowDialog () в потоке пользовательского интерфейса и используйте ProgressChanged для обновления окна ProgressWindow.
чтобы получить ProgressForm для самостоятельного закрытия, в backgroundWorker1_RunWorkerCompleted, вызовите f.Close (); это означает длинный операция завершена, и мы можем закрыть окно.
здесь необходимо не передавать всю основную форму классу, а просто экземпляр вашего BackgroundWorker! Вам нужно бросить отправителя в качестве фонового работника, например:
private void bgWorker_DoWork(object sender DoWorkEventArgs e)
{
// Get the BackgroundWorker that raised this event
BackgroundWorker worker = sender as BackgroundWorker;
// And now you just send worker to whatever class you need like so:
bgArgs args = e.Argument as bgArgs;
MyClass objMyClass = new MyClass();
MyClass.MyMethod(strValue, args.Option, worker);
// Do something based on return value.
}
и затем в MyClass.MyMethod()
вы бы сделали вычисления прогресса и просто подняли worker.ReportProgress(int percentage)
событие, чтобы обновить индикатор выполнения или еще что - то в вашей основной форме пользовательского интерфейса!
это должно работать отлично!
проверьте эту статью MSDN для получения более подробной информации, см. Их Пример Фибоначчи, это то, что они делают с CalculateFibonacci
- это пользовательский класс, который отправляет обновления в интерфейс основной формы.
посмотреть MSDN BackgroundWorker Class для получения более подробной информации.