На данный вопрос уже ответили:
Как заставить работать вывод в Label/TextBox в многопоточном режиме?
Происходит считывание и обработка директории с файлами, чью динамику показывает Progressbar. Хочу чтобы параллельно с заполнением этой полоски прогресс бара выводилась процентовка относительно количества обработанных файлов. Однако, процент выводится только в самом конце (100%) никаких промежуточных процентов не выводится.
delegate void Print(string str);
private void Form1_Load(object sender, EventArgs e) {
Print p1 = (string str) => { label1.Text += str; };
var fb =new FolderBrowserDialog();
fb.ShowDialog();
var dir=new DirectoryInfo(fb.SelectedPath);
var files = dir.GetFileSystemInfos();
progressBar1.Maximum = files.Length;
foreach(var f in files) {
hand(f.FullName);
progressBar1.Value++;
//1)
label1.Text = Convert.ToDouble(progressBar1.Value/ progressBar1.Maximum)*100+"%";
//2)
//Task.Run(() => { DoSomething(); });
//3)
//label1.Invoke(p1, new object[] { (progressBar1.Value / progressBar1.Maximum) * 100 + "%" });
}
}
public void DoSomething() {
if (label1.InvokeRequired) {
label1.Invoke(new Action(DoSomething));
}
else {
label1.Text = Convert.ToDouble(progressBar1.Value / progressBar1.Maximum) * 100 + "%";
}
}
Для этих целей можно использовать класс BackgroundWorker, его метод ReportProgress а также события. Пример использования ниже.
public partial class Form1 : Form
{
BackgroundWorker bgw = new BackgroundWorker();
public Form1()
{
InitializeComponent();
label1.Text = "";
label2.Text = "";
}
private void button1_Click_1(object sender, EventArgs e)
{
bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
bgw.ProgressChanged += new ProgressChangedEventHandler(bgw_ProgressChanged);
bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);
bgw.WorkerReportsProgress = true;
bgw.RunWorkerAsync();
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
int total = 57; //some number (this is your variable to change)!!
for (int i = 0; i <= total; i++) //some number (total)
{
System.Threading.Thread.Sleep(100);
int percents = (i * 100) / total;
bgw.ReportProgress(percents, i);
//2 arguments:
//1. procenteges (from 0 t0 100) - i do a calcumation
//2. some current value!
}
}
void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
label1.Text = String.Format("Progress: {0} %", e.ProgressPercentage);
label2.Text = String.Format("Total items transfered: {0}", e.UserState);
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//do the code when bgv completes its work
}
}
UPDATE:
Как верно предложил @Сергей, можно реализовать обновление на Task'ах:
private bool complete = false;
private int fileProgress = 0;
private int totalProgress = 100;
private async void button1_Click(object sender, EventArgs e)
{
await Task.WhenAll(Task.Factory.StartNew(()=> {
while (!complete)
{
if (fileProgress != 0 && totalProgress != 0)
{
//Here you signal the UI thread to execute the action:
progressBar1.Invoke((Action)(() =>
{
//This is done by the UI thread:
var a = (((double)fileProgress / (double)totalProgress) * 100);
progressBar1.Value = Convert.ToInt32(a);
label1.Text = a.ToString();
}));
}
}
}),
Task.Factory.StartNew(()=> {
for (int i = 0; i < totalProgress; i++)
{
fileProgress++;
Thread.Sleep(3000);
}
complete = true;
}
));
MessageBox.Show("Done"); //here we're on the UI thread.
}
Я пользуюсь для этого таким способом. Не знаю насколько это правильно. Допустим у нас есть некий класс, в котором что-то происходит (фоновый процесс о ходе которого необходимо уведомлять).
public class Rename
{
...
public event Action<int> ProcessChanged;
public void ABC()
{
...
ProcessChanged(i);
...
}
...
}
В основном классе создаем объект подписываемся на событие
Rename.ProcessChanged += FileOper_ProccesChanged;
private void FileOper_ProccesChanged(int progress)
{
Action action = () =>
{
PGBar_Music.Value = progress;
};
if (InvokeRequired)
Invoke(action);
else
action();
}
Сборка персонального компьютера от Artline: умный выбор для современных пользователей