Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用WinForms进度条?_C#_Winforms_Progress Bar - Fatal编程技术网

C# 如何使用WinForms进度条?

C# 如何使用WinForms进度条?,c#,winforms,progress-bar,C#,Winforms,Progress Bar,我想显示在外部库中执行的计算的进度 例如,如果我有一些calculate方法,并且我想在我的Form类中对100000个值使用它,我可以写: public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Caluculate(int i) { double pow = Math.P

我想显示在外部库中执行的计算的进度

例如,如果我有一些calculate方法,并且我想在我的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();
        }
    }
}
公共部分类表单1:表单
{
公共表格1()
{
初始化组件();
}            
私人无效计算(int i)
{
double-pow=Math.pow(i,i);
}
私有无效按钮1\u单击(对象发送者,事件参数e)
{
progressBar1.最大值=100000;
progressBar1.步骤=1;
对于(int j=0;j<100000;j++)
{
计算(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);
    }
}
公共部分类表单1:表单
{
公共表格1()
{
初始化组件();
}
私有void CaluculateAll(System.Windows.Forms.ProgressBar ProgressBar)
{
progressBar.最大值=100000;
progressBar.Step=1;
对于(int j=0;j<100000;j++)
{
双功率=数学功率(j,j);//计算
progressBar.PerformStep();
}
}
私有无效按钮1\u单击(对象发送者,事件参数e)
{
CaluculateAll(progressBar1);
}
}

但是我不想那样做。

我建议你看看。如果你的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.
}
private void计算(int i)
{
double-pow=Math.pow(i,i);
}
私有无效按钮1\u单击(对象发送者,事件参数e)
{
progressBar1.最大值=100;
progressBar1.步骤=1;
progressBar1.值=0;
backgroundWorker.RunWorkerAsync();
}
私有void backgroundWorker_DoWork(对象发送方,DoWorkEventArgs e)
{
var backgroundWorker=发送方作为backgroundWorker;
对于(int j=0;j<100000;j++)
{
计算(j);
后台工作人员报告进度((j*100)/100000);
}
}
private void backgroundWorker_ProgressChanged(对象发送方,ProgressChangedEventArgs e)
{
progressBar1.值=e.ProgressPercentage;
}
私有void backgroundWorker_RunWorkerCompleted(对象发送方,runworkercompletedeventarge)
{
//TODO:对最终计算做些什么。
}

自.NET 4.5以来,您可以使用与的组合向UI线程发送更新:

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
}
private void计算(int i)
{
double-pow=Math.pow(i,i);
}
公共无效工作(i进度)
{
//此方法在的上下文中执行
//另一个线程(与主UI线程不同),
//所以只使用线程安全代码
对于(int j=0;j<100000;j++)
{
计算(j);
//使用progress通知UI线程已完成进度
//改变
如果(进度!=null)
进度报告((j+1)*100/100000);
}
}
私有异步无效按钮1\u单击(对象发送方,事件参数e)
{
progressBar1.最大值=100;
progressBar1.步骤=1;
变量进度=新进度(v=>
{
//此lambda在UI线程的上下文中执行,
//因此,它可以安全地更新表单控件
progressBar1.值=v;
});
//在另一个线程中运行操作
等待任务。运行(()=>DoWork(progress));
//托多:算了算,还是做点什么吧
}
任务是当前实现
BackgroundWorker
功能的首选方式

此处将更详细地说明任务和
进度

  • 斯蒂芬·克利里

嘿,有一个关于网络珍珠的有用教程:

与Peter的意见一致,您需要使用一些线程,否则程序将挂起,这在某种程度上违背了目的

使用ProgressBar和BackgroundWorker的示例:C#

使用System.ComponentModel;
使用系统线程;
使用System.Windows.Forms;
命名空间Windows窗体应用程序1
{
公共部分类Form1:Form
{
公共表格1()
{
初始化组件();
}
私有void Form1_加载(对象发送方,System.EventArgs e)
{
//启动后台工作人员。
backgroundWorker1.RunWorkerAsync();
}
私有void backgroundWorker1\u DoWork(对象发送方,DoWorkEventArgs e)
{

对于(int i=1;i存在
任务
,使用
BackgroundWorker
是不必要的,
任务
更简单。例如:

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.
}
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();
var progressDialog=newprogressdialog();
progressDialog.Progressbar.Value=0;
progressDialog.Progressbar.Maximum=100;
progressDialog.RunAsync(()=>
{
对于(int i=0;i<100;i++)
{
线程。睡眠(1000)
this.progressDialog.Progressbar.BeginInvoke((MethodInvoker)(()=>{
this.progressDialog.Progressbar.Value+=1;
}));
}
});
progressDialog.ShowDialog();

将委托对象传递给该方法。这应该是所选的答案,依我看。答案很好!几乎是最好的答案,只是它使用的是Task.Run而不是普通的asyncfunction@KansaiRobot您的意思是与
await-doworksync(进度)相反
?这是故意的,因为这不会导致额外的线程运行。只有
DoWorkAsync
会调用自己的
wait
,例如等待I/O操作时,
按钮1\u单击
函数才能继续。主UI线程在此期间被阻塞。如果
DoWorkAsync
不是真的异步,但有很多