分享
 
 
 

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

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

使用多线程加载多个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_queue.remove();//从队列中移出文件

}

Thread.Sleep(500);

}

}

请注意上面的QueueMonitorThread线程,他自己不处理文件。只是检测队列,如果有文件存在就调用parse方法,而parse方法为每个文件处理生成一个线程。

方法内容如下:

private void parse(FileInfo info)

{

//返回一个线程

Thread t = parserThread.CreateThread (new parserThread.Start(parserMethod), info);

t.Start ();

//阻塞调用线程

t.Join (Timeout.Infinite);

}

下面是创建线程的类:

public class parserThread

{

//代理代参数的方法

public delegate void Start (object obj);

//这个类用来解决ThreadStart只能代理无参数无返回值函数而设计。

private class Argument

{

public object obj1;//用来保存文件名数据

public Start s1;

//建立该方法是为了由ThreadStart来代理,

public void parse()

{

s1(obj1);

}

}

//创建返回线程。

public static Thread CreateThread (Start s, Object arg1)

{

Argument arg = new Argument();

arg.obj1 = arg1;

arg.s1 = s;

Thread t = new Thread (new ThreadStart (arg.parse));

return t;

}

}

下面是parserMethod方法:

public void parserMethod(object obj)

{

FileInfo fInfo = (FileInfo)obj;

process_xml((fInfo.fName));

}

如果你看了ParserThread类的CreateThread方法,那上面的parserMethod方法就很清楚了。我们成功的完成了参数的传递。下面是process_xml方法:

public void process_xml(String name)

{

try

{

XmlDocument doc = new XmlDocument();

String fname = name;

doc.Load(fname);

XmlNodeList nList1;

XmlNodeList nList2;

XmlNodeList nList;

nList=doc.GetElementsByTagName("EmpDataSet");

for( int m =0;m<nList.Count;m++)

{

XmlElement element_main = (XmlElement)nList.Item(m);//emp_table

nList1 = element_main.ChildNodes ;//Emps

for( int k =0;k<nList1.Count;k++)

{

XmlElement element_fchild = (XmlElement)nList1.Item(k);

nList2 = element_fchild.ChildNodes ;

IEmpDetails emp = new EmpDetails();

if( m_bAbort)

{

return;

}

for( int j =0;j<nList2.Count;j++)

{

XmlElement child_element = (XmlElement)nList2.Item(j);

if( child_element.Name == "Emp_id" )

{

emp.empId = System.Convert.ToInt32(child_element.InnerText);

}

if( child_element.Name == "Emp_Name" )

{

emp.empName = child_element.InnerText;

}

if( child_element.Name == "Emp_Address" )

{

emp.empAddress = child_element.InnerText;

}

if( child_element.Name == "Emp_City" )

{

emp.empCity = child_element.InnerText;

}

if( child_element.Name == "Emp_State" )

{

emp.empState = child_element.InnerText;

}

if( child_element.Name == "Emp_Pin" )

{

emp.empPin = child_element.InnerText;

}

if( child_element.Name == "Emp_Country" )

{

emp.empCountry = child_element.InnerText;

}

else if( child_element.Name == "Emp_Email" )

{

emp.empEmail = child_element.InnerText;

}

}

//切换线程到TreeView所被创建的线程,从而更新TreeView,不过这里是异步的。

BeginInvoke(onTreeViewElement, new object[] {this, new ThreadEventArgs(emp)});

}

}

}

catch(Exception exp)

{

MessageBox.Show("Error...in displaying treeview "+exp.Message);

}

}

EmpDetails类实现了IEmpDetails接口,用来包含数据,略。

BeginInvoke方法异步执行,里面通过代理onTreeViewElement来调用populateTreeView方法:

private void populateTreeView(object sender, ThreadEventArgs e)

{

IEmpDetails ex = e.empDetails;

TreeNode n = new TreeNode("EMP :"+ex.empId);

n.Nodes.Add(ex.empName);

n.Nodes.Add(ex.empAddress);

n.Nodes.Add(ex.empCity);

n.Nodes.Add(ex.empState);

n.Nodes.Add(ex.empPin);

n.Nodes.Add(ex.empCountry);

n.Nodes.Add(ex.empEmail);

treeView1.Nodes.Add(n);

}

另外一个就是参数类,用来传输xml文件的内容:

public class ThreadEventArgs : EventArgs

{

IEmpDetails _empDetails;

public IEmpDetails empDetails

{

get{ return _empDetails;}

}

public ThreadEventArgs(IEmpDetails empDetails)

{

this._empDetails = empDetails;

}

}

结论:这个例子里面的设计对于显示大量的文件是很有用的。这里又一个限制就是一旦点击了终止按纽,监视线程就会终止。要使能够再次使用需要重其应用程序。

希望这篇文章里面的一些思想对你会有所帮助(带参数调用线程和创建多线程任务)。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有