经常做WinForm开发的人可能会遇到这样一种情况,WinForm程序后台有许多线程在执行任务,前台界面需要适时或定时显示后台任务执行的情况。此类任务界面通常如下:  利用数据绑定(DataBinding)简化多线程数据展示_数据

这里存在一个问题是如何在界面上显示后台线程上的状态数据,也就是多线程如何访问控件。

  .NET中的控件并不是线程安全的,因此我们通常是用如下方法在界面上显示后台线程的数据:






​1​

private​ ​void​ ​​Test(​​​string​ ​​val) { ​


​2​

if​ ​​(txtSuccess.InvokeRequired) { ​


​3​

​txtSuccess.Invoke((ShowVal)Test,val); ​


​4​

​} ​


​5​

else​ ​​{ ​


​6​

​txtSuccess.Text = val; ​


​7​

​} ​


​8​

​}​


此类方法存在一些问题:

  1,更新代码比较多,且比较晦涩难懂,不易维护;

  2,如果后台状态经常发生变动,则涉及到需要更改的代码可能比较多,如赋值代码,相关委托;

  3,后台线程中除了维护状态外还需显世更新前台界面,造成后台线程代码冗余;

  那么有没有一种比较好的解决方法呢?答案就是数据绑定。通过数据绑定,后台线程只需要维护任务状态而不需要关心这些数据如何显示,而前台界面仅需要不断更新显示数据,而不必关心数据更新来自何方。

  下面以一个简单的例子说明如何利用数据绑定(DataBinding)简化多线程数据展示,假设后台有2个线程在不断处理任务,同时记录了任务执行成功,失败的情况,前台则需要动态显示这些任务的执行状况。任务类简单定义为:






​1​

public​ ​class​ ​​TaskEntity { ​


​2​

private​ ​int​ ​​_TaskId = 0; ​


​3​

private​ ​int​ ​​_TaskSuccess = 0; ​


​4​

private​ ​int​ ​​_TaskFail = 0; ​


​5​

public​ ​int​ ​​TaskId { ​​​get​ ​​{ ​​​return​ ​​_TaskId; } ​​​set​ ​​{ _TaskId = value; } } ​


​6​

public​ ​int​ ​​TaskSuccess { ​​​get​ ​​{ ​​​return​ ​​_TaskSuccess; } ​​​set​ ​​{ _TaskSuccess = value; } } ​


​7​

public​ ​int​ ​​TaskFail { ​​​get​ ​​{ ​​​return​ ​​_TaskFail; } ​​​set​ ​​{ _TaskFail = value; } } ​


​8​

public​ ​int​ ​​TaskAll { ​​​get​ ​​{ ​​​return​ ​​_TaskSuccess + _TaskFail; } } ​


​9​

​}​


  然后定义一个全局的数据源用于存放这些任务的引用,同时将该数据源邦定到前台界面上






​01​

public​ ​​List<TaskEntity> dataSource; ​


​02​

private​ ​​TaskEntity task1; ​


​03​

private​ ​​TaskEntity task2; ​


​04​

private​ ​void​ ​​InitializeDataSource() { ​


​05​

​dataSource = ​​​new​ ​​List<TaskEntity>(); ​


​06​

​task1 = ​​​new​ ​​TaskEntity(); ​


​07​

​task1.TaskId = 0; ​


​08​

​dataSource.Add(task1); ​


​09​

​task2 = ​​​new​ ​​TaskEntity(); ​


​10​

​task2.TaskId = 1; ​


​11​

​dataSource.Add(task2); ​


​12​

​} ​


​13​

private​ ​void​ ​​InitializeBinding() { ​


​14​

​dataGridView1.DataSource = dataSource; ​


​15​

​txtAll.DataBindings.Add(​​​new​ ​​Binding(​​​​"Text"​​​​,task1,​​​​"TaskAll"​​​​)); ​


​16​

​txtFail.DataBindings.Add(​​​new​ ​​Binding(​​​​"Text"​​​​, task1, ​​​​"TaskFail"​​​​)); ​


​17​

​txtSuccess.DataBindings.Add(​​​new​ ​​Binding(​​​​"Text"​​​​, task1, ​​​​"TaskSuccess"​​​​)); ​


​18​

​}​


  然后启动2个后台线程






​01​

private​ ​​Thread thread1; ​


​02​

private​ ​​Thread thread2; ​


​03​

void​ ​​btnBS_Click(​​​object​ ​​sender, EventArgs e) { ​


​04​

​workStatus = !workStatus; ​


​05​

if​ ​​(workStatus) { ​


​06​

​thread1 = ​​​new​ ​​Thread(Dowork1); ​


​07​

​thread1.Start(); ​


​08​

 


​09​

​thread2 = ​​​new​ ​​Thread(Dowork2); ​


​10​

​thread2.Start(); ​


​11​

​} ​


​12​

​}​


  最后定义数据更新方法





​view source​


​print​​​​?​


​1​

private​ ​void​ ​​UpdateControlValue() { ​


​2​

​dataGridView1.Invalidate(); ​


​3​

​txtAll.DataBindings[0].ReadValue(); ​


​4​

​txtFail.DataBindings[0].ReadValue(); ​


​5​

​txtSuccess.DataBindings[0].ReadValue(); ​


​6​

​}​


 

  做完这些后就可以点击验证,执行结果如下:

 

利用数据绑定(DataBinding)简化多线程数据展示_.NET_02

  最后通过比对2种方法的实现,执行结果,可以得出,在.NET中利用数据绑定(DataBinding)可以简化多线程数据展示,使得代码的可维护性更高,对于新人也更容易入手。当然,示例中也存在一些问题,如更新不及时,帮定数据源有限制等。但是想比解决的问题,这些代价完全可以承受,并且通过添加简单的同步代码就可以解决。