외부 라이브러리에서 수행되는 계산의 진행 상황을 보여주고 싶습니다.
예를 들어 계산 메서드가 있고 Form 클래스의 100000 값에 사용하려면 다음과 같이 작성할 수 있습니다.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Caluculate(int i)
{
double pow = Math.Pow(i, i);
}
private void button1_Click(object sender, EventArgs e)
{
progressBar1.Maximum = 100000;
progressBar1.Step = 1;
for(int j = 0; j < 100000; j++)
{
Caluculate(j);
progressBar1.PerformStep();
}
}
}
계산 후 단계를 수행해야합니다. 그러나 외부 방법으로 100000 개의 계산을 모두 수행하면 어떨까요? 이 방법이 진행률 표시 줄에 종속되지 않도록하려면 언제 “단계를 수행”해야합니까? 예를 들어 다음과 같이 쓸 수 있습니다.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void CaluculateAll(System.Windows.Forms.ProgressBar progressBar)
{
progressBar.Maximum = 100000;
progressBar.Step = 1;
for(int j = 0; j < 100000; j++)
{
double pow = Math.Pow(j, j); //Calculation
progressBar.PerformStep();
}
}
private void button1_Click(object sender, EventArgs e)
{
CaluculateAll(progressBar1);
}
}
하지만 그렇게하고 싶지 않습니다.
답변
BackgroundWorker를 살펴보실 것을 제안합니다 . WinForm에 큰 루프가 있으면 차단되고 앱이 중단 된 것처럼 보입니다.
봐 BackgroundWorker.ReportProgress()
UI 스레드로 진행 등을보고하는 방법을 볼 수 있습니다.
예를 들면 :
private void Calculate(int i)
{
double pow = Math.Pow(i, i);
}
private void button1_Click(object sender, EventArgs e)
{
progressBar1.Maximum = 100;
progressBar1.Step = 1;
progressBar1.Value = 0;
backgroundWorker.RunWorkerAsync();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
var backgroundWorker = sender as BackgroundWorker;
for (int j = 0; j < 100000; j++)
{
Calculate(j);
backgroundWorker.ReportProgress((j * 100) / 100000);
}
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// TODO: do something with final calculation.
}
답변
.NET 4.5부터는 UI 스레드에 업데이트를 보내기 위해 Progress 와 함께 async 및 await 조합을 사용할 수 있습니다 .
private void Calculate(int i)
{
double pow = Math.Pow(i, i);
}
public void DoWork(IProgress<int> progress)
{
// This method is executed in the context of
// another thread (different than the main UI thread),
// so use only thread-safe code
for (int j = 0; j < 100000; j++)
{
Calculate(j);
// Use progress to notify UI thread that progress has
// changed
if (progress != null)
progress.Report((j + 1) * 100 / 100000);
}
}
private async void button1_Click(object sender, EventArgs e)
{
progressBar1.Maximum = 100;
progressBar1.Step = 1;
var progress = new Progress<int>(v =>
{
// This lambda is executed in context of UI thread,
// so it can safely update form controls
progressBar1.Value = v;
});
// Run operation in another thread
await Task.Run(() => DoWork(progress));
// TODO: Do something after all calculations
}
작업은 현재 수행하는 작업을 구현하는 데 선호되는 방법 BackgroundWorker
입니다.
작업
Progress
은 여기에 자세히 설명되어 있습니다.
답변
Dot Net pearls에 대한 유용한 튜토리얼이 있습니다 : http://www.dotnetperls.com/progressbar
Peter와 동의하여 약간의 스레딩을 사용해야합니다. 그렇지 않으면 프로그램이 중단되어 목적이 다소 무너집니다.
ProgressBar 및 BackgroundWorker를 사용하는 예 : C #
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, System.EventArgs e)
{
// Start the BackgroundWorker.
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= 100; i++)
{
// Wait 100 milliseconds.
Thread.Sleep(100);
// Report progress.
backgroundWorker1.ReportProgress(i);
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Change the value of the ProgressBar to the BackgroundWorker progress.
progressBar1.Value = e.ProgressPercentage;
// Set the text.
this.Text = e.ProgressPercentage.ToString();
}
}
} //closing here
답변
거기에 Task
그것은 사용 unnesscery이며, 존재 BackgroundWorker
, Task
더 간단합니다. 예를 들면 :
ProgressDialog.cs :
public partial class ProgressDialog : Form
{
public System.Windows.Forms.ProgressBar Progressbar { get { return this.progressBar1; } }
public ProgressDialog()
{
InitializeComponent();
}
public void RunAsync(Action action)
{
Task.Run(action);
}
}
끝난! 그런 다음 어디에서나 ProgressDialog를 다시 사용할 수 있습니다.
var progressDialog = new ProgressDialog();
progressDialog.Progressbar.Value = 0;
progressDialog.Progressbar.Maximum = 100;
progressDialog.RunAsync(() =>
{
for (int i = 0; i < 100; i++)
{
Thread.Sleep(1000)
this.progressDialog.Progressbar.BeginInvoke((MethodInvoker)(() => {
this.progressDialog.Progressbar.Value += 1;
}));
}
});
progressDialog.ShowDialog();