哪里有做图片的网站,wordpress数据库密码修改,镇江企业网站排名优化,外贸网站优化谷歌关键词排名在WinForm项目中#xff0c;很多时候会映遇上多线程一起工作的情况#xff0c;因为当前UI的更新显示#xff0c;是在主线程中#xff0c;一但主线程被长时运算占据后#xff0c;UI就会被卡信#xff0c;出现假死现像。那么就需要起一个新线程做长时运算工作#xff0c;把…在WinForm项目中很多时候会映遇上多线程一起工作的情况因为当前UI的更新显示是在主线程中一但主线程被长时运算占据后UI就会被卡信出现假死现像。那么就需要起一个新线程做长时运算工作把进度或数据同步回UI线程。以一个医保上传数据为例功能是同步药品器械诊疗项目同步完后进行验证核对。注为了看得清晰各个关键控件我没有重命名定义一个list来充当步骤和需要时间。static ListItem list;
private void Form1_Load(object sender, EventArgs e)
{list new ListItem{new Item{ Name正在上传诊疗项目,Time8 },new Item{ Name正在上传器材,Time12 },new Item{ Name正在上传药品,Time20 },new Item{ Name正在核对,Time24 },};
}第一版用Task.Run来启动一个新的线程中的for循环是为了表示一个进度的...的切换如果换成一个gif图标更佳foreach循环是完成list中各项任务的。如果运行你会发现窗体上是空白的18行的给messageLabel.Text不起作用。private void button1_Click(object sender, EventArgs e)
{Task.Run(() {foreach (var item in list){var dotString ;for (var i 0; i item.Time; i){if (i % 6 0){dotString .;}else{dotString .;}messageLabel.Text ${item.Name}{dotString};SpinWait.SpinUntil(() false, 300);}}MessageBox.Show(完成医保所有数据同步);});
}第二版为了更新UI线程在新线程中用this.Invoke来更新UI上控件的值如18行。这回没有什么问题了UI也能即时更新看上去很完美。private void button2_Click(object sender, EventArgs e)
{Task.Run(() {foreach (var item in list){var dotString ;for (var i 0; i item.Time; i){if (i % 6 0){dotString .;}else{dotString .;}this.Invoke(() {messageLabel.Text ${item.Name}{dotString};});SpinWait.SpinUntil(() false, 300);}}MessageBox.Show(完成医保所有数据同步);});
}其实这背后是有异常的有可能会在vs中报出来因为当你关闭窗体时18行的this已经不存在了但访问this.Invoke在新的线程中新线程本身并没有关掉这时就会报找不到实例有可能你运行起来并不会发现异常这是因为主线程关闭后所有创建的子线程都会关闭的为了验证你可以5行前面加一个try在catch中把异常内容写在一个日志文件中。我的结果是Cannot access a disposed object.
Object name: Form1.第三版发现问题那就解决吧有可能你觉得无所谓窗体都关闭了没报异常看不出来。确实如果你觉得无所谓那就无所谓这里只是来说明技术点的不是来说服想法的通过一个mark标志在关闭窗体时拦截一下把子线程关闭然后再把主窗体关闭这样就没有问题了自己起的线程自己要关掉。static bool mark true;
private void startButton_Click(object sender, EventArgs e)
{Task.Run(() {foreach (var item in list){if (mark false){break;}var dotString ;for (var i 0; i item.Time; i){if (mark false){break;}if (i % 6 0){dotString .;}else{dotString .;}this.Invoke(() {messageLabel.Text ${item.Name}{dotString};});SpinWait.SpinUntil(() false, 300);}}if (mark){mark false;MessageBox.Show(完成医保所有数据同步);}else{this.Invoke(() {this.Close();});}});
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{if (mark){e.Cancel true;mark false;}
}线程是个大话题这只是简单的线程协同两个线程没有深度协同。通过这个例子三个版本一步一步来满足功能提升健壮性和安全性我们们可以得出做了一个功能是需要下功夫的不但要知其然还要知其所以然。