我有一个Windows窗体应用程序,它创建一个后台线程来搜索文件并将匹配的文件名添加到DataGridView。后台线程使用BeginInvoke向DataGridView添加行,如果后台线程没有返回数千个结果,一切正常。即使后台线程处理数千个文件,UI也能正常工作,除非它尝试向DataGridView输入几千行。
我尝试逐个添加行,并缓冲它们并一次添加100行。但是应用程序UI始终没有响应。后台进程比UI线程工作得更快,并且总有新行要添加到DataGridView。
我甚至尝试过Application.DoEvents(在UI线程中),但它也没有帮助。
有什么想法吗?我可以在不向后台线程添加延迟的情况下修复它吗?
提前致谢
答案 0 :(得分:2)
确保分别在添加所有新行之前和之后调用SuspendLayout()
和ResumeLayout()
。在添加所有行之前不调用SuspendLayout
,DataGridView
将在每个添加的行之后重新绘制自己,这会使事情变慢一些。
答案 1 :(得分:2)
看起来使用Invoke而不是BeginInvoke来添加行是最简单的解决方案。它稍微减慢了后台线程,但它阻止了UI无响应。 由于您没有向后台线程添加预定义的延迟,我认为将后台线程减慢一点只是为了让UI线程赶上来是可以接受的。 使用SuspendLayout和ResumeLayout在使用BeginInvoke时也没有帮助。 我没有尝试使用共享行的虚拟模式,但这也可能有所帮助。
答案 2 :(得分:1)
答案 3 :(得分:0)
一种方法是让主线程创建一个BlockingCollection<string>
,作为后台线程可以添加字符串的队列。后台线程完成添加后,会调用CompleteAdding
。
UI线程还会创建一个以某种频率触发的计时器(可能是您通过实验确定的)。计时器的Elapsed
事件会查看队列中是否有任何内容,如果有,则删除一个项目并将其添加到DataGridView
。当计时器的Elapsed
事件看到队列的IsComplete
属性为True
时,它会停止并处理计时器。
提供你的计时器不会做得太快,这应该保持你的UI响应,你不必摆弄后台线程的延迟。
答案 4 :(得分:0)
我遇到的问题似乎是每次添加一行时滚动条会重新绘制自己,如果我添加let就像10000行一样。我通过在填充之前将datagridview的滚动条设置为None来解决此问题,并在填充后进行恢复,如下所示:
ScrollBars bars = this.ScrollBars; this.ScrollBars = System.Windows.Forms.ScrollBars.None;
...在这里填充(我有一个覆盖的DataGridView控件)
this.ScrollBars = bars;
在添加数千行的情况下,SuspendLayout因某些原因无效。