日期:2008-07-05  浏览次数:20403 次

使用多线程加载多个XML文件到TreeView控件



原代码:LoadingXMLInTvMTCode.zip




在很多情况下程序员需要采用多线程来开发应用程序,用户可以在前台操作数据或其他工作,在后台程序正在加载很大的一些文件,而这一过程不会影响到前台的用户。在这篇文章中,我来讲述一下怎样通过多个线程来加载多个文件。



在这个例子中我们将来研究这样一件事情,读取多个XML文件并通过TreeView把它们显示出来。我们可以通过数据库来完成,不过为了保持例子的简单这里采用了XML文件。



你会注意到我们有两个XML文件同原代码放在一起。

程序用户界面如下:






Filedisplayer类用来显示上面的窗体。窗体的包括一些按纽:浏览按纽,运行按纽,终止按纽以及退出按纽。应用程序可以通过点击退出按纽来结束整个程序的运行。当点击浏览的时候会打开一个文件选择对话框来加载XML文件。当然你也可以直接在文本框中输入文件全路径。

private void selectbutton_click(object sender, System.EventArgs e)

{

OpenFileDialog openFileDialog1 = new OpenFileDialog();

openFileDialog1.Filter = "All Files (*.*)|*.*|Text Files (*.txt)|*.txt";

if (openFileDialog1.ShowDialog () == DialogResult.OK)

{

String fileName = openFileDialog1.FileName;

//如果文件扩展名为XML,选择成功

if ( (fileName.Length != 0) && (fileName.EndsWith("XML")))

{

filename_box.Text=fileName;

}

}

}



一旦选择了一个文件,用户可以通过点击运行来读取文件数据。显示的结果就如上面TreeView中所看到的。这篇文章的主要目的就是给读者一个方法来执行多线程。终止按纽用来退出执行的任务。



现在我们已经习惯的各种用户界面控件,那就让我们来研究其他部分。你可以在代码中注意到我们已经编写了下面一些代码(如下):

private Thread QueueMonitorThread ;//定义一个线程,用来监视队列

private RequestQueue req_queue;//放了加载的文件信息(文件名)

private bool m_bAbort;//通过这标志来控制 QueueMonitorThread

private ThreadEventDelegate onTreeViewElement;//异步代理调用,切换线程来更新TreeView

在RequestQueue.CS文件中我们定义了一个RequestQueue类,他是一个队列用来存储文件名数据。在这个例子中设置了队列的容量为5。因此队列最多能放五个文件名在里面。在Add方法中有一个逻辑,如果添加文件成功返回1,如果失败(队列为满)返回0;Remove方法用来移动队列头索引,如果头索引等与尾索引那队列就为空了;getFile方法是用来获取队列最前面的项。如果为空返回0, setSize方法用来重新设置队列的容量,如果调用原来的数据就会被扔掉(这里作者是用数组来模拟环形队列,设置容量会重新实例化一个数组);isEmpty方法用来判断队列是否有空。



备注:你也可以使用System.Collections命名空间下的Queue类。



当点击了运行按纽后,程序会从获取路径文本框中获取文件名并把它加入到FileInfo结构(很奇怪这里作者的结构只是存了一个string)。最后把这个结构加入到了队列。QueueMonitorThread线程会半秒钟去扫描一次队列。

private void processbutton_click(object sender, System.EventArgs e)

{

FileInfo f = new FileInfo();

f.fName=this.filename_box.Text;

//如果队列已满那就等待队列有空时再添加FilInfo

while ( req_queue.isEmpty()!=1)

{

if( req_queue.isEmpty() == 1 )

break;

Thread.Sleep(200);

}

req_queue.add(f);

}

下面是继承窗体的构造函数。

public filedisplayer()

{

InitializeComponent();

req_queue = new RequestQueue();

//设置队列容量为5

req_queue.setSize(5);

//默认监视线程没有终止

m_bAbort = false;

//实例会监视线程

QueueMonitorThread = new Thread( new ThreadStart(QueueMonitorfunc));

QueueMonitorThread.Start();

//代理更新TreeView,BeginInvoke

onTreeViewElement = new ThreadEventDelegate(populateTreeView);

}



下面是线程的执行方法。

public void QueueMonitorfunc()

{

while( true)

{

if(isAbort())//判断线程是否跳出循环,结束线程

{

break;

}

Object o = req_queue.getFile();//从队列获取文件

if( (o is FileInfo ))//队列是否为空

{

FileInfo f = (FileInfo)req_queue.getFile();

string filename = f.fName;

parse(f);//启动一个线程处理

req_que