多线程中操作主界面控件问题解决等待的问题

.Net技术 码拜 8年前 (2016-04-30) 1000次浏览
界面处理大量数据,需要用多线程。
但是在线程中给界面赋值总是 报错。怎么样解决。界面不假死,不是单纯后台不假死。
Control.CheckForIllegalCrossThreadCalls = false;
用这个可以达到预期想要的效果,但是不安全,一旦用到复杂的代码怕报错,所以不想用这种方式。
假如 Control.CheckForIllegalCrossThreadCalls = true;  给某些界面控件赋值的时候就会报错。
问一下怎么样实现处理界面的时候可以赋值,并且界面不是假死状态。
注意:本人是用多线程是处理主界面,例如 txtBox = “100000”;  (例如 这个操作需要3秒,这个代码执行的时候界面不能假死,打个比方而已)。
delegate void AsyncGetDataDelegate();
//在线程里处理代码
private void GetData()
{
PeelerssPoDetail peerpodtil = new PeelerssPoDetail();
DataTable db = peerpodtil.GetPoDtilList(ParmFilter());
dgvData.DataSource = db;    //这个过程不能假死
}
private void btnAny_Click(object sender, EventArgs e)
{
try
{
//执行异步线程
AsyncGetDataDelegate adl = new AsyncGetDataDelegate(GetData);
adl.BeginInvoke(new AsyncCallback(GetResult), adl);

}
catch
{
}
}
至于为什么要这种效果这是另一回事,只想解决界面赋值的时候不假死!

解决方案

3

那就本人写控件吧

1

首先,你这样的代码
private void btnAny_Click(object sender, EventArgs e)
{
try
{
//执行异步线程
AsyncGetDataDelegate adl = new AsyncGetDataDelegate(GetData);
adl.BeginInvoke(new AsyncCallback(GetResult), adl);

}
catch
{
}
}
其实是毫无意义的,而且它肯定比直接从 UI 线程调用更慢。你这个是使用了异步多线程操作的语法,里模拟一个同步调用过程。虽然你的 btnAny_Click 立刻就结束了,但是你的整个操作都注册到 UI 主线程去排队,然后仍然在主线程去执行。你这就相当于一个在超市收银台付款的人从排队的第一位跑回了队尾重新排队,却自认为本人跑到另外一个空闲的队列中了!这不更慢嘛!
一个正常的多线程编程,是把大量时间用在子线程处理数据操作上,例如1秒钟来处理数据。然后一瞬间(例如5毫秒)输出界面操作的语句注册给 UI 线程去执行。而你这种把全部操作都注册给 UI 主线程的做法,画蛇添足,更慢。

1

引用:
Quote: 引用:

最后本人要忠告你一句,不要胡写 try…catch 代码。多余地写这个代码,要比错误地使用“异步多线程”更严重。乱写 try…catch 说明你没有学过调试、测试技术,那样你才会接受一个完全错误的(自欺欺人的)的概念。
程序在调试、测试阶段,就是要让异常尽可能早一点地跳出来,这是学习编程开发时一定要学会的基本理念。因此能够不写 try..catch 的地方一定不要写 try…catch。跳出异常是令人兴奋的,原因是它告诉你怎么样将产品快速重构而提高质量。只有 Release 编译版本才在程序最边界(表现层最外边)来捕获并处理异常提示,因此使用“条件编译”来让个别代码在 Release 版本时才真正出现在编译版本之中。
相反,那些认为在本人什么都不懂时、刚刚编程时就考虑“欺骗用户”的try…catch写法,不但没有欺骗用户,反而是首先欺骗了本人。原因是你不知道程序为什么带病继续工作、为什么随后乱成一团。你想让公司的老板和技术经理不知道你的程序有多危险,除非他们是傻子才会不能一眼看出你写了多余的 try…catch 代码的目的是什么。

你说的有道理,不过try catch
包括那个代码是随便写一下试试举例子的。具体不是这样的。
胡乱加上的。不用放在心上,只是打个比方而已。
其实目的很简单。目的 就是想办法 怎么让让 界面不假死,主要不是为了速度!
所以本人后面不是说了么,暂且不用纠结为什么要这么做,确实有这方面需求,说来话长,里面还有很多细节。
本人想问一下可以实现么。总不能本人写中断实现这个目的么?

为了提高用户体验,用时较长的操作放到单独线程中去,
防止阻塞主线程,界面长时间无响应,
后台处理完成后,通过委托来与UI交互

1

引用:

相似 界面要不停的动那种!同时执行。
在主线程排队?仍然在主线程去执行?
那不对啊,Control.CheckForIllegalCrossThreadCalls = false;
的时候 没有假死。而是 可以操作主界面,而且 数据也 同时一点点 显示。同时执行。
难不成 主线程 每隔0.00000秒先执行 1个,然后再执行 另一个,那么来回执行让本人看不出来?那也不对啊!原因是本人操作的时候 没假死。
应该是分配了另一个线程 去执行 一个任务,然后 完成了,再通知,
例如 你 委派 收银员 去买菜,你继续干你的活,买完菜通知你。本人是这么理解的。

CheckForIllegalCrossThreadCalls只是关闭了跨线程调用的检查,假如这个属性本身是不能跨线程赋值的话,可能会出现难以解释的错误

14

处理过程除非必要的进度显示,不要调用和UI相关的属性,需要更新界面时使用委托跨线程,担心效率的话把ui更新的委托设为异步的就好

2

这么简单一个问题绕到现在,其实sp1234在#2说得很清楚了。

private void GetData()
 {
            //下面两句跑在新建线程
            PeelerssPoDetail peerpodtil = new PeelerssPoDetail();
            DataTable db = peerpodtil.GetPoDtilList(ParmFilter());    
           
           //这句跑在UI线程
            dgvData.DataSource = db;    //这个过程不能假死
}

那么大致改成这样就行了:

delegate DataTable AsyncGetDataDelegate();
 //在线程里处理代码
private DataTable GetData()
{
            PeelerssPoDetail peerpodtil = new PeelerssPoDetail();
            return  peerpodtil.GetPoDtilList(ParmFilter());
}
private void btnAny_Click(object sender, EventArgs e)
 {
            AsyncGetDataDelegate d = new AsyncGetDataDelegate(GetData);
            d.BeginInvoke(ia => dgvData.DataSource = d.EndInvoke(ia), null);
}

10

Control.CheckForIllegalCrossThreadCalls 等于 true 还是 false,只是所谓能否线程安全的问题
windows 中的程序,本来就是分有 线程安全 和 非线程安全 的版本的。且后者的运行速度要明显高于前者
本人不知道你在开发一个多么复杂的系统,也不知道你已经遇到了什么问题
但是你始终没有提到跨线程访问公共资源时的共享冲突问题
要主界面不假死,就得将耗时工作放到子线程中去
子线程访问主线程元素时,就得将其锁住(lock)
尽管 C# 提供了各种各样的手段,那都只是为了使用起来方便。防止共享冲突的锁,总是要存在的,不管你看见看不见

8

BackGroundWorker有这样一个组件,可以了解一下。本人经常做Winform项目,主程序启动了,数据就是让这个来执行异步操作,主界面不会死,而且也会加快启动速度。

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明多线程中操作主界面控件问题解决等待的问题
喜欢 (0)
[1034331897@qq.com]
分享 (0)