C#.NET,技巧篇(DataGridView线程操作)

这个系列的文章,主要是平时做C#.NET(Framework 3.5)开发的时候,积累的经验和技巧。我们平时总有这样的体会,遇到一个特别难解决的问题,网上寻它千百度也没能搜索到有用的信息。这时你肯定会想,解决了这个问题一定要记下来。实际上待你埋头苦干终于搞定它的时候,往往被喜悦和成就感充斥,再加上这个问题本身解决的方法可能简单无比,于是忘记去记录下来。本篇就从零开始,回顾五年编程经验积累的各种奇葩问题的解决方法。

 

DataGridView是个神奇的控件,与数据集绑定显示,方便、耐用。但是这样一个封装了99%内部实现的控件,必然会出现你让你抓狂的异常。

来看今天遇到的问题:主窗口有一个DataGridView控件,它的DataSource是atable;在线程中获取一行数据arow,添加到atable中,然后invoke主线程去修改MainForm上一个Label的Text。线程函数代码如下:

threadfun()

{

	//......



	atable.AddRow(arow);



	Invoke(adelegate);



	//......

}

 

测试exe程序的时候出现主界面无响应的情况,反复重启发现每当添加第N条数据后问题出现,N是某个定值。使用VS调试源代码,问题消失。

做C#开发最难受的情况就是,VS调试一切OK,运行exe出错。这种情况我们以后会经常遇到,可以理解为.Net Framework的运行时和调试时是略有不同的,不再深入追究。使用VS附加进程调试,找到源头是invoke的委托代码执行被挂起,导致主界面无响应。

 

解决方法:在线程中,对DataGridView的数据源进行的操作都使用委托。

分析:数据表atable是DataGridView的数据源,DataGridView是主线程的控件,虽然在线程函数里可以访问同一命名空间下的引用,但是一旦牵扯到控件,最好还是让主线程去操作,否则就会出现各种意想不到的问题,比如今天遇到的。

刨根问底:向atable添加一行arow,这会导致DataGridView重绘,因为绑定的数据源自动显示。从这个角度来看,今天的例子犯了一个常见的错误:从线程修改主线程控件。特殊的地方是这个重绘操作是.Net内部通过某种机制实现的,它并不违反约束,前N-1次操作并没有异常发生就能看出来。那么,为什么第N次添加操作就一定会触发这个问题呢?

真相:通过观察视图设计,我发现第N条数据会使DataGridView自动添加纵向滚动条,为了验证这是否是真相,我减小了DataGridView的高度,果然小于第N条数据就出现了问题,从而确定就是这个添加滚动条的动作导致主线程挂起,窗口无响应。

总结:想弄明白这个问题的最终答案,必须完全理解DataGridView的内部实现机制,这个机制允许从线程向DataGridView添加行并显示,但是当自动创建滚动条的时候会挂起,我想这也算是一个bug了吧。从我们开发者自身角度来讲,保持一个良好的编程习惯至关重要——线程不访问其他线程的变量,必须访问的时候所有操作都用委托。如果上述例子的开发者能遵循这个原则,就不会遇到这个难题。

你可能感兴趣的:(datagridview)