当前位置: 首页 > 编程语言 > C#

如何在C#中传输数据包时正确保持UI更新?分享

时间:2023-04-10 22:46:10 C#

C#中如何在传输数据包时正确保持UI更新?我有这种形式,它产生一个新线程,并开始侦听并循环等待UDP数据包。我需要的是根据接收到的字节数更新UI。为此,我设置了一个事件,该事件在收到数据包后立即引发,并将收到的字节数作为参数传递。由于我没有在UI线程上运行,所以我不能简单地直接更新UI。这是我目前正在做的事情:privatevoidEVENTHANDLER_UpdateTransferProgress(longreceivedBytes){if(InvokeRequired){Invoke(newMethodInvoker(()=>{totalReceivedBytes+=receivedBytes;Label.Text=totalReceivedBytes.ToString("##,0");}));但这仍然在与数据包接收循环相同的线程上运行,并且它不会返回到该循环-并等待另一个数据包-直到此EVENTHANDLER_UpdateTransferProgress方法返回。我的问题基本上是关于上述方法中的以下行:Label.Text=totalReceivedBytes.ToString("##,0");像这样更新UI会减慢数据包接收速度。如果我取消注释该行(或注释它),数据包接收会更快。我怎么可能解决这个问题?我认为更多的多线程是关键,但我不确定在这种情况下如何正确地实现它们……我正在使用带有.NET2.0的Windows窗体。编辑:在我之前的测试中,以上内容似乎是正确的,并且在某种程度上可能实际上是正确的。但是经过一些测试,我意识到问题出在整个Invoke(newMethodInvoker(()=>{...}));事物。当我删除它(当然不更新UI)并保留EVENTHANDLER_UpdateTransferProgress但继续引发事件时,数据包接收速度更快。我测试了接收一些文件,在不调用事件处理程序上的Invoke()的情况下平均需要大约1.5秒。当我在事件处理程序中调用Invoke()时,即使没有更新UI中的任何控件或执行任何操作(换句话说,匿名方法主体为空),它也需要更长的时间,大约5.5秒。你可以看到它有很大的不同。无论如何要改善这个?您的方法的问题在于它会在每个数据包中更新UI。如果每秒接收1000个数据包,则每秒更新UI1000次!显示器每秒可能不会刷新超过100次,如果每秒刷新超过10次,则没有人能够读取它。解决这个问题的更好方法是将totalReceivedBytes+=receivedBytes;在处理I/O的线程中,并在执行Label.Text=totalReceivedBytes.ToString("##,0");的UI线程上放置一个计时器;Label.Text=totalReceivedBytes.ToString("##,0");最多每秒几次。当传输开始时,启动定时器;当传输停止时,停止计时器。是的,有一种方法可以改善这一点。第一种是使用BeginInvoke而不是Invoke,后者不等待调用返回。您还应该考虑在方法中使用另一种形式返回;}totalReceivedBytes+=receivedBytes.TotalReceivedBytes;Label.Text=total("##,0");因此,如果从不需要调用的方法中调用此方法,则仍会执行GUI上的更新。您可以做的另一个选择是销毁下载线程中的线程。类似于公共事件EventHandlerReportProgress;publicvoidstartSendingUpdates(MonitorEventArgsargs){EventHandlerhandler=ReportProgress;如果(处理程序==null){返回;}ThreadPool.QueueUserWorkItem(delegate{while(!args.Complete){handler(this,args);Thread.Sleep(800);}});}publicvoiddownload(){MonitorEventArgsargs=newMonitorEventArgs();开始发送更新(args);while(downloading){intread=downloadData(bytes);+=阅读;}args.Complete=true;}publicclassMonitorEventArgs:EventArgs{publicboolComplete{get;放;}publiclongBytesTransferred{get;放;与收益相比,这种开销很小。您的下载线程不受GUI更新的影响(至少与等待GUI更新相比)。缺点是您在线程池中占用了一个线程,但是,嘿,这就是它们的用途!并且,线程在完成后关闭,因为您设置了完整标志。设置时也不需要锁,因为工作线程中的额外运行在上下文中并不重要。您是否尝试过使用BeginInvoke而不是Invoke?BeginInvoke()是一个异步调用。以上是C#学习教程:C#传输数据包时如何正确保持UI更新?如果分享的内容对你有用,需要了解更多C#学习教程,希望你多多关注——=>{totalReceivedBytes+=receivedBytes;Label.Text=totalReceivedBytes.ToString("##,0");}));}}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: