不知道为什么没有刷新 要等函数执行完毕之后才刷新 感觉很奇怪
刚试了下 用两条MessageBox.show()可以显示 也就是说并非函数执行完毕之后才能执行 类似于阻塞 想问下怎么解决界面刷新的问题
#region 旧版解决方案
private void Button1_Click(object sender, EventArgs e) {
((Action)ProgressBar1).BeginInvoke((org) => { //进度条逻辑要用一个异步线程,如果直接在UI线程中循环操作,UI会出现假死,并且只显示最后一个值
MessageBox.Show("进度条执行完毕"); //由于是异步的,这里不会阻塞
}, null);
}
void ProgressBar1() {
int i = 0;
do {
i++;
//在异步线程中,不能直接操作控件,需要到控件所在的线程上通过异步委托进行操作
label1.Invoke((Action)(() => {
label1.Text = i + "%";
}));
Thread.Sleep(50);
} while (i < 100);
}
#endregion
#region 新版async await,简单
private async void Button2_Click(object sender, EventArgs e) {
await ProgressBar2();
MessageBox.Show("进度条执行完毕后才会弹出");
}
async Task ProgressBar2() {
int i = 0;
do {
i++;
label1.Text = i + "%";
await Task.Delay(50);
} while (i < 100);
}
#endregion
上午的时候看到了这些代码 很感谢大佬提供的这些思路和代码 很清晰
试过label标签的属性确实能够这样赋值 不过进度条并不支持 所以百度异步 如图所示 创建新线程去处理进度条值的改变 也通过打印确定了确实是两个不同的线程 但是执行的时候还是不太对
我的理解是button里的线程是主线程 而我创建的线程 也就是th 是分支线程 当分支线程完成的时候 再执行主线程 但看起来好像是 分支线程执行完毕之后会等待主线程执行完毕 最后在关闭线程释放内存的时候才会按照我的想法关闭 前后不对导致UI并没有正常刷新 强制关闭分支线程报错.....想问一下这种情况应该怎么处理
@Miss云: 不是很明白你的意思,使用多线程就是为了实现异步效果,异步没有先后,多个线程是同时执行
private void Button1_Click(object sender, EventArgs e) {
//Thread th = new Thread(AAA);
//th.Start();
//使用原始都得Thread可以创建一个新的线程,但是无法在该线程之心完毕后再做些什么操作
//如果使用委托调用BeginInvoke,就能传入一个回调函数,执行该线程执行完毕后的操作
((Action)AAA).BeginInvoke((org => {
MessageBox.Show("进度条走完了");
}), null);
MessageBox.Show("这里不会影响进度条,因为他们是不同的线程");
}
void AAA() {
for (int i = 0; i < 100; i++) {
Invoke(new Action(delegate () {
progressBar1.Value++;
}));
Thread.Sleep(50); //这个放外面避免界面卡顿
}
}
private async void Button2_Click(object sender, EventArgs e) {
await BBB();
MessageBox.Show("进度条走完了");
}
async Task BBB() {
int i = 0;
do {
i++;
progressBar1.Value = i;
await Task.Delay(50);
} while (i < 100);
}
@WmW: 这两个方法我都试了下 第一个是.net 6.0不支持委托开启 第二个的效果和我之前的效果一致
其实遇到的问题一直是 进度条的值达到了最大 但是进度条UI并没有更新 也就是看起来没满 等待弹窗弹出来之后才刷新 视觉效果就是进度条还没跑完弹窗就出来了
我需要的是进度条更新完毕(也就是进度条满了之后)再弹窗 所以本质上是同步执行 看到你的代码和注释之后了解到 进度条的值需要异步赋值刷新 所以便新建线程(th)去处理进度条的赋值问题 但是效果并不理想 依旧是 值达到最大 但是进度条控件并没有满 弹窗之后进度条才满 想问一下为什么控件没有随值的改变而更新 是需要绑定数据才会实时更新嘛
@Miss云: 我也不知道什么问题了,我这边看上去没有问题
@WmW: 有没有一种可能 就是说 Windows11 他......哈哈哈 我去虚拟机上试试 谢谢了
是不是应该把执行的内容放到一个子线程去执行, 进度条用委托到ui线程刷新, 你现在这不都是在ui现成内呢, 委托也没用吧
我去试试 Python用太多了 这个C#完全忘完了 不刷新的原因是因为单线程来不及刷新嘛
this.invoke 放到循环外面去,你这又没用多线程,也不用invoke呀。不用线程,50个大小值,又不sleep,是瞬间完成的。
Thread th=new Thread(()=>{
this.Invoke(new Action(()=>{
for (int i = 0; i < 50; i++){
progressBar1.Value++;
Thread.Sleep(300);
}
}))
});
th.Start();
试了一下 其实值和弹窗什么的都能正常运行 不太清楚为啥界面更新的比实际值慢一点
@Miss云: 你是怎么判断这个快慢的
@HelloLLLLL: 先是视觉效果看起来进度条未满 然后弹窗就出现了 然后打断点才发现进度条的实际值已经达到最大 但是界面进度条未满 所以怀疑是界面更新问题
@Miss云: for循环结束的时候,加一句 progressBar1.Value=progressBar1.MaxSize
@HelloLLLLL: 找到原因了 在UI设计界面直接更改进度条的Value值 发现有一个动画过程 也就是说进度条赋值会有一个动画效果 但是我找不到修改这个动画播放属性的地方(自己在搜资料的时候也看到了很多人吐槽这个进度条的动画效果) 于是只能回到最开始的延时操作 最后用异步等待的方式完成
不过也大致弄清楚了Threading和Threading.Tasks的区别 sleep和wait的区别 还有就是二楼提供的async await 方法 确实好用 不过最好还是自定义控件 动画效果不能改太折磨人了 最后 谢谢啦 我去看看委托到底是怎么一回事
谢谢各位大佬 真好
– Miss云 2年前