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

kuaile999 2016-07-11 11:37:16
界面处理大量数据,需要用多线程。
但是在线程中给界面赋值总是 报错。如何解决。界面不假死,不是单纯后台不假死。

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
{

}
}

至于为什么要这种效果这是另一回事,只想解决界面赋值的时候不假死!
...全文
395 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
未来为我而来 2020-01-14
  • 打赏
  • 举报
回复
Delta 2016-07-13
  • 打赏
  • 举报
回复
BackGroundWorker有这样一个组件,可以了解一下。我经常做Winform项目,主程序启动了,数据就是让这个来执行异步操作,主界面不会死,而且也会加快启动速度。
kuaile999 2016-07-12
  • 打赏
  • 举报
回复
引用 9 楼 happycaily 的回复:
处理过程除非必要的进度显示,不要调用和UI相关的属性,需要更新界面时使用委托跨线程,担心效率的话把ui更新的委托设为异步的就好
通信程序!类似地铁控制,路灯控制,车辆定位!轨迹跟踪。数控,类似。必须界面跑线程。
CailyPersonal 2016-07-12
  • 打赏
  • 举报
回复
引用 17 楼 kuaile999 的回复:
[quote=引用 16 楼 happycaily 的回复:] [quote=引用 14 楼 kuaile999的回复:][quote=引用 13 楼 happycaily 的回复:] [quote=引用 10 楼 kuaile999的回复:][quote=引用 9 楼 happycaily 的回复:] 处理过程除非必要的进度显示,不要调用和UI相关的属性,需要更新界面时使用委托跨线程,担心效率的话把ui更新的委托设为异步的就好
通信程序!类似地铁控制,路灯控制,车辆定位!轨迹跟踪。数控,类似。必须界面跑线程。 [/quote] ui肯定有线程,我的意思是数据处理之类的不要由ui线程去跑,ui只负责顶层的显示,用后台线程跑通信之类的[/quote] 抱歉说错了,我的意思,界面不能假死!在UI线程上执行,必假死无疑! 我的目的就是让界面不假死,不停的处理数据,同时我还在主界面上还能做别的。至于为什么要这么做是另一外一回事。 希望指教一下,谢谢[/quote] 我不知道具体的,看了下你说的,是不是在进行源赋值的时候时间长,源比较大。如果是这样子我建议你重写下控件,单独写一下源的过程,毕竟赋值过程ui线程得有不少看不到的步骤。 还有你的这个赋值过程界面操作不是很理解,你假定的是不是赋值过程消耗时间长了,感觉就像假死一样。[/quote] 可能我举得例子不对,给你误导了,实际不是处理数据用。目的就是为了不让界面假死,但是数据也很频繁。 同一个界面 比如 我在监控中心要监控车辆在地图上的位置, 车辆的数据通过TCP,IP方式传过来,我后台设置监控程序,捕获车辆的数据,再把车辆的数据解析成经度、纬度。然后再显示在地图上或者界面上以文字显示等........界面不停的显示车辆的位置,我不停的监控。 于此同时可能做一些其他操作,比如状态栏还有进度条在干别的,显示进度。同时我还可能发控制命令去控制一些 设备的开关(监控的数据很多,做其它的操作也很多,控制中心) 数据可能 1秒传一次,或者 N秒传输一次,当然不光是这些可能还有些其他要处理的,此时 如果 给主界面赋值一次,卡一下。那就无法实现监控这类程序的操作了。 主要程序不能等待 就好比游戏,比如拳皇对战游戏吧,A 与 B对战,A动的时候B也要动。总不能A动的时候,B不能动吧,当然了游戏应该是采用 中断实现的,比如A 动0.000001秒,A停止,然后B动0.000001秒,然后B定制,再A动...反复如此.表面上看起来不等待。 WINDOWS操作系统本身也是多线程的。 希望指教一下! [/quote] 我好像明白了,你的多线程也是用了,只是UI层面需要关联的东西比较多,担心一个部分会影响另一个部分。 两种办法,使用多窗口,硬性把它们区分开来,相当于多UI,防止单个UI线程某部分的卡顿对其它UI的影响。 第二种从单线程性能考虑。这种方案就需要把和显示相关的东西做到最简化,比如你说的,实时监测,是不是可以考虑显示层面的刷新速率低些;再比如,你说的其它操作,是不是可以将操作底下的实际步骤交与非UI线程去执行。思想就是UI线程只能响应显示和操作相关的东西,但是具体显示需要的东西,包括计算不在UI线程。非实时监控的其它操作可以只响应按钮,但是按下做的事情全部交与非UI线程去执行。目的就是减小UI线程的工作负荷。 如果按照第二种,应该会用到多个后台线程,但是UI就会好得多
xuzuning 2016-07-12
  • 打赏
  • 举报
回复
Control.CheckForIllegalCrossThreadCalls 等于 true 还是 false,只是所谓是否线程安全的问题 windows 中的程序,本来就是分有 线程安全 和 非线程安全 的版本的。且后者的运行速度要明显高于前者 我不知道你在开发一个多么复杂的系统,也不知道你已经遇到了什么问题 但是你始终没有提到跨线程访问公共资源时的共享冲突问题 要主界面不假死,就得将耗时工作放到子线程中去 子线程访问主线程元素时,就得将其锁住(lock) 尽管 C# 提供了各种各样的手段,那都只是为了使用起来方便。防止共享冲突的锁,总是要存在的,不管你看见看不见
kuaile999 2016-07-12
  • 打赏
  • 举报
回复
引用 16 楼 happycaily 的回复:
[quote=引用 14 楼 kuaile999的回复:][quote=引用 13 楼 happycaily 的回复:] [quote=引用 10 楼 kuaile999的回复:][quote=引用 9 楼 happycaily 的回复:] 处理过程除非必要的进度显示,不要调用和UI相关的属性,需要更新界面时使用委托跨线程,担心效率的话把ui更新的委托设为异步的就好
通信程序!类似地铁控制,路灯控制,车辆定位!轨迹跟踪。数控,类似。必须界面跑线程。 [/quote] ui肯定有线程,我的意思是数据处理之类的不要由ui线程去跑,ui只负责顶层的显示,用后台线程跑通信之类的[/quote] 抱歉说错了,我的意思,界面不能假死!在UI线程上执行,必假死无疑! 我的目的就是让界面不假死,不停的处理数据,同时我还在主界面上还能做别的。至于为什么要这么做是另一外一回事。 希望指教一下,谢谢[/quote] 我不知道具体的,看了下你说的,是不是在进行源赋值的时候时间长,源比较大。如果是这样子我建议你重写下控件,单独写一下源的过程,毕竟赋值过程ui线程得有不少看不到的步骤。 还有你的这个赋值过程界面操作不是很理解,你假定的是不是赋值过程消耗时间长了,感觉就像假死一样。[/quote] 可能我举得例子不对,给你误导了,实际不是处理数据用。目的就是为了不让界面假死,但是数据也很频繁。 同一个界面 比如 我在监控中心要监控车辆在地图上的位置, 车辆的数据通过TCP,IP方式传过来,我后台设置监控程序,捕获车辆的数据,再把车辆的数据解析成经度、纬度。然后再显示在地图上或者界面上以文字显示等........界面不停的显示车辆的位置,我不停的监控。 于此同时可能做一些其他操作,比如状态栏还有进度条在干别的,显示进度。同时我还可能发控制命令去控制一些 设备的开关(监控的数据很多,做其它的操作也很多,控制中心) 数据可能 1秒传一次,或者 N秒传输一次,当然不光是这些可能还有些其他要处理的,此时 如果 给主界面赋值一次,卡一下。那就无法实现监控这类程序的操作了。 主要程序不能等待 就好比游戏,比如拳皇对战游戏吧,A 与 B对战,A动的时候B也要动。总不能A动的时候,B不能动吧,当然了游戏应该是采用 中断实现的,比如A 动0.000001秒,A停止,然后B动0.000001秒,然后B定制,再A动...反复如此.表面上看起来不等待。 WINDOWS操作系统本身也是多线程的。 希望指教一下!
CailyPersonal 2016-07-12
  • 打赏
  • 举报
回复
引用 14 楼 kuaile999的回复:
[quote=引用 13 楼 happycaily 的回复:] [quote=引用 10 楼 kuaile999的回复:][quote=引用 9 楼 happycaily 的回复:] 处理过程除非必要的进度显示,不要调用和UI相关的属性,需要更新界面时使用委托跨线程,担心效率的话把ui更新的委托设为异步的就好
通信程序!类似地铁控制,路灯控制,车辆定位!轨迹跟踪。数控,类似。必须界面跑线程。 [/quote] ui肯定有线程,我的意思是数据处理之类的不要由ui线程去跑,ui只负责顶层的显示,用后台线程跑通信之类的[/quote] 抱歉说错了,我的意思,界面不能假死!在UI线程上执行,必假死无疑! 我的目的就是让界面不假死,不停的处理数据,同时我还在主界面上还能做别的。至于为什么要这么做是另一外一回事。 希望指教一下,谢谢[/quote] 我不知道具体的,看了下你说的,是不是在进行源赋值的时候时间长,源比较大。如果是这样子我建议你重写下控件,单独写一下源的过程,毕竟赋值过程ui线程得有不少看不到的步骤。 还有你的这个赋值过程界面操作不是很理解,你假定的是不是赋值过程消耗时间长了,感觉就像假死一样。
kuaile999 2016-07-12
  • 打赏
  • 举报
回复
引用 12 楼 qbilbo 的回复:
前面忘了写invoke了...
private void btnAny_Click(object sender, EventArgs e)
{
            AsyncGetDataDelegate d = new AsyncGetDataDelegate(GetData);
            d.BeginInvoke(ia =>
                dgvData.Invoke(new MethodInvoker(()=>dgvData.DataSource = d.EndInvoke(ia)))
            , null);
}
如果你的VS版本是2012或以上。 那可以更简单的写成:
private async void button_click(object sender, EventArgs e)
{
      dgvData.DataSource = await Task.Run<DataTable>(() => GetData());
}
我只是用这个代码打个比方。可能举得例子不恰当 dgvData.Invoke 相当于在 控件的线程上执行。委托封送只是解决给主界面赋值问题,赋值的过程中还需要等待,我不要这个等待过程,等待期间我要能干别的。 dgvData.DataSource = db比如需要3秒。这3秒 我处于等待状态,不能操作主界面上的其它东西。 我的目的让这个 dgvData.DataSource = db一边执行,我还可以在主界面上干别的。否则我要等dgvData.DataSource = db完成才能做别的。 一般线程处理后台 ,我是处理前台界面。
kuaile999 2016-07-12
  • 打赏
  • 举报
回复
引用 13 楼 happycaily 的回复:
[quote=引用 10 楼 kuaile999的回复:][quote=引用 9 楼 happycaily 的回复:] 处理过程除非必要的进度显示,不要调用和UI相关的属性,需要更新界面时使用委托跨线程,担心效率的话把ui更新的委托设为异步的就好
通信程序!类似地铁控制,路灯控制,车辆定位!轨迹跟踪。数控,类似。必须界面跑线程。 [/quote] ui肯定有线程,我的意思是数据处理之类的不要由ui线程去跑,ui只负责顶层的显示,用后台线程跑通信之类的[/quote] 抱歉说错了,我的意思,界面不能假死!在UI线程上执行,必假死无疑! 我的目的就是让界面不假死,不停的处理数据,同时我还在主界面上还能做别的。至于为什么要这么做是另一外一回事。 希望指教一下,谢谢
CailyPersonal 2016-07-12
  • 打赏
  • 举报
回复
引用 10 楼 kuaile999的回复:
[quote=引用 9 楼 happycaily 的回复:] 处理过程除非必要的进度显示,不要调用和UI相关的属性,需要更新界面时使用委托跨线程,担心效率的话把ui更新的委托设为异步的就好
通信程序!类似地铁控制,路灯控制,车辆定位!轨迹跟踪。数控,类似。必须界面跑线程。 [/quote] ui肯定有线程,我的意思是数据处理之类的不要由ui线程去跑,ui只负责顶层的显示,用后台线程跑通信之类的
qbilbo 2016-07-12
  • 打赏
  • 举报
回复
前面忘了写invoke了...
private void btnAny_Click(object sender, EventArgs e)
{
            AsyncGetDataDelegate d = new AsyncGetDataDelegate(GetData);
            d.BeginInvoke(ia =>
                dgvData.Invoke(new MethodInvoker(()=>dgvData.DataSource = d.EndInvoke(ia)))
            , null);
}
如果你的VS版本是2012或以上。 那可以更简单的写成:
private async void button_click(object sender, EventArgs e)
{
      dgvData.DataSource = await Task.Run<DataTable>(() => GetData());
}
qbilbo 2016-07-12
  • 打赏
  • 举报
回复
这么简单一个问题绕到现在,其实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);
}
  • 打赏
  • 举报
回复
最后我要忠告你一句,不要胡写 try...catch 代码。多余地写这个代码,要比错误地使用“异步多线程”更严重。乱写 try...catch 说明你没有学过调试、测试技术,那样你才会接受一个完全错误的(自欺欺人的)的概念。 程序在调试、测试阶段,就是要让异常尽可能早一点地跳出来,这是学习编程开发时一定要学会的基本理念。因此能够不写 try..catch 的地方一定不要写 try...catch。跳出异常是令人兴奋的,因为它告诉你如何将产品快速重构而提高质量。只有 Release 编译版本才在程序最边界(表现层最外边)来捕获并处理异常提示,因此使用“条件编译”来让个别代码在 Release 版本时才真正出现在编译版本之中。 相反,那些认为在自己什么都不懂时、刚刚编程时就考虑“欺骗用户”的try...catch写法,不但没有欺骗用户,反而是首先欺骗了自己。因为你不知道程序为什么带病继续工作、为什么随后乱成一团。你想让公司的老板和技术经理不知道你的程序有多危险,除非他们是傻子才会不能一眼看出你写了多余的 try...catch 代码的目的是什么。
  • 打赏
  • 举报
回复
其次,相关地,你说的 txtBox = "100000"; (比如 这个操作需要3秒 虽然你这是打比方,但极端不合理,从这里已经可以看出你没有去理解细节了。 只要稍微深入一点点,就可以解决问题。而不深入,那么就把时间浪费在皮毛上了。
  • 打赏
  • 举报
回复
首先,你这样的代码 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 主线程的做法,画蛇添足,更慢。
Poopaye 2016-07-11
  • 打赏
  • 举报
回复
那就自己写控件吧
CailyPersonal 2016-07-11
  • 打赏
  • 举报
回复
处理过程除非必要的进度显示,不要调用和UI相关的属性,需要更新界面时使用委托跨线程,担心效率的话把ui更新的委托设为异步的就好
Poopaye 2016-07-11
  • 打赏
  • 举报
回复
引用 7 楼 kuaile999 的回复:
类似 界面要不停的动那种!!同时执行。 在主线程排队?仍然在主线程去执行? 那不对啊,Control.CheckForIllegalCrossThreadCalls = false; 的时候 没有假死。而是 可以操作主界面,而且 数据也 同时一点点 显示。同时执行。 难不成 主线程 每隔0.00000秒先执行 1个,然后再执行 另一个,那么来回执行让我看不出来?那也不对啊!因为我操作的时候 没假死。 应该是分配了另一个线程 去执行 一个任务,然后 完成了,再通知, 比如 你 委派 收银员 去买菜,你继续干你的活,买完菜通知你。我是这么理解的。
CheckForIllegalCrossThreadCalls只是关闭了跨线程调用的检查,如果这个属性本身是不能跨线程赋值的话,可能会出现难以解释的错误
kuaile999 2016-07-11
  • 打赏
  • 举报
回复
类似 界面要不停的动那种!!同时执行。 在主线程排队?仍然在主线程去执行? 那不对啊,Control.CheckForIllegalCrossThreadCalls = false; 的时候 没有假死。而是 可以操作主界面,而且 数据也 同时一点点 显示。同时执行。 难不成 主线程 每隔0.00000秒先执行 1个,然后再执行 另一个,那么来回执行让我看不出来?那也不对啊!因为我操作的时候 没假死。 应该是分配了另一个线程 去执行 一个任务,然后 完成了,再通知, 比如 你 委派 收银员 去买菜,你继续干你的活,买完菜通知你。我是这么理解的。
xian_wwq 2016-07-11
  • 打赏
  • 举报
回复
引用 5 楼 kuaile999 的回复:
[quote=引用 4 楼 sp1234 的回复:] 最后我要忠告你一句,不要胡写 try...catch 代码。多余地写这个代码,要比错误地使用“异步多线程”更严重。乱写 try...catch 说明你没有学过调试、测试技术,那样你才会接受一个完全错误的(自欺欺人的)的概念。 程序在调试、测试阶段,就是要让异常尽可能早一点地跳出来,这是学习编程开发时一定要学会的基本理念。因此能够不写 try..catch 的地方一定不要写 try...catch。跳出异常是令人兴奋的,因为它告诉你如何将产品快速重构而提高质量。只有 Release 编译版本才在程序最边界(表现层最外边)来捕获并处理异常提示,因此使用“条件编译”来让个别代码在 Release 版本时才真正出现在编译版本之中。 相反,那些认为在自己什么都不懂时、刚刚编程时就考虑“欺骗用户”的try...catch写法,不但没有欺骗用户,反而是首先欺骗了自己。因为你不知道程序为什么带病继续工作、为什么随后乱成一团。你想让公司的老板和技术经理不知道你的程序有多危险,除非他们是傻子才会不能一眼看出你写了多余的 try...catch 代码的目的是什么。
你说的有道理,不过try catch 包括那个代码是随便写一下试试举例子的。具体不是这样的。 胡乱加上的。不用放在心上,只是打个比方而已。 其实目的很简单。目的 就是想办法 怎么让让 界面不假死,主要不是为了速度! 所以我后面不是说了么,暂且不用纠结为什么要这么做,确实有这方面需求,说来话长,里面还有很多细节。 我想问一下可以实现么。总不能自己写中断实现这个目的么?[/quote] 为了提高用户体验,用时较长的操作放到单独线程中去, 防止阻塞主线程,界面长时间无响应, 后台处理完成后,通过委托来与UI交互
加载更多回复(1)

110,533

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧