我在一个方法里给一个进度条加进度同时给label1赋值 可是进度条可以一点一点改变,label1的值在代码里有改变 可是在窗体里无法显示,只能在整个方法运行完后才能显示出最后的100% 怎么才能和进度条同步显示
private void BYStu(DataTable SetDt)
{
if (SetDt != null)
{
int i = SetDt.Rows.Count;
i = 100 / i;
foreach (DataRow SetDtRow in SetDt.Rows)
{
progressBar1.Value = progressBar1.Value + i;
label1.Text = progressBar1.Value+"%";
Thread.Sleep(1000);
}
}
}
private void BYStu(DataTable SetDt)
{
if (SetDt != null)
{
int i = SetDt.Rows.Count;
i = 100 / i;
foreach (DataRow SetDtRow in SetDt.Rows)
{
progressBar1.Value = progressBar1.Value + i;
label1.Text = progressBar1.Value+"%";
Thread.Sleep(1000);
}
}
}
Application.DoEvents();
应用到的有Control.BeginInvoke和Delegate.BeginInvoke方法。思路是这样。
1、先定义一个delegate
public void delegate ByStuDelegate(DataTable dt);
当点击某个按钮或什么,开始异步执行ByStu()方法。
ByStuDelegate del = new ByStuDelegate(ByStu);
del.BeginInvoke(dt, null, null);2、还需要一个delegate
public void ShowProgressDelegate(int cur, int total);private int cur = 0; //当前处理到哪儿了。
private int total; //总共有多少数据。
private void BYStu(DataTable SetDt)
{
foreach (DataRow SetDtRow in SetDt.Rows)
{
DoSomething(); // 对SetDtRow进行某种操作
cur++;
ShowProgress(cur, total); //调用ShowProgress,更新ProgressBar等.
}
}private void ShowProgress(int cur, int total)
{
if(this.InvokeRequired)
{
//这里自己调用自己,为什么,自己查资料。
ShowProgressDelegate del = new ShowProgressDelegate(ShowProgress);
del.BeginInvoke(cur, total);
}
else
{
progressBar.Value = (int)((double)cur/(double)total * 100); //语法对不对?差不多,反正;
progressBar.Maximum = total;
label1.Text = "进度:" + cur + "/" + tatal;
}
}也就大概这样子啦。差不多明白后,可以把这一套当作定式记下来~呵呵。
if(this.InvokeRequired)
{
//这里自己调用自己,为什么,自己查资料。
ShowProgressDelegate del = new ShowProgressDelegate(ShowProgress);
this.BeginInvoke(cur, total); //这里应用到的是Control.BeginInvoke方法
}
this.BeginInvoke(del, new object[] { cur, total});
(EndXXX在程序员眼里有两个作用:1)获得返回值;2)检测过程中任何异常
但是在.NET设计师眼里,还有一个重要的作用:释放内部异步操作所占用的资源)所以你的(1),即定义并且调用原方法的委托,必须改成另一种设计(注:如果冗长工作的最后是有返回值的,你就一定会调用EndInvoke了,就不需要修改这个设计了)例如使用ThreadPool首先,将原方法的参数包装成一个object,
例如如果原方法为 void XXXXX(int a, long b, DateTime c, Stream d)
则需要弄一个参数包装类
class XXXXXParameters{
public int a { get; }
public long b { get; }
public DateTime c { get; }
public Stream d { get; }
}
然后创建实例将参数都包装进来
但是因为本例中,参数只有一个,那就不需要包装了然后,使用ThreadPool将这个方法放入待处理队列中:
ThreadPool.QueueUserWorkItem(new WaitCallback(原方法), 参数包装对象);然后,
void 原方法(object state) // 符合 WaitCallback 的签名
{
XXXXXParameters parameters = (XXXXXParameters)state;
// 现在就可以通过 parameters 对象获取各个参数值了 -- or -- DataTable SetDt = (DataTable)state; // 这是只有一个参数的时候的便捷方式 // 然后就开始处理吧
// 要往UI线程送中途状态或最终结果就记得用 Control.BeginInvoke
}