|
|||||
|
|||||
在Framework2.0中,跨线程进行访问控件时,编译器会检查你所使用的方法是否线程安全。如VS2003那样直接无视线程赋值和取值的话,编译器会报错,提示线程不安全。几乎所有初次接触多线程WINFORM编程的人都碰到过这样的问题。 发生这类情况的时候,就可以使用委托和事件来回调创建该控件的线程中的方法。 所有控件都继承自 System.Windows.Form.Control类,而在Control类中已经包含了一系列线程安全的解决方案。 Control.InvokeRequired: Control.Invoke(delegate, object [] params): Control.BeginInvoke() & Control.EndInvoke():
跨线程读取: class ThreadDemo1 //要执行的线程
...{ private string[] _file; public string[] Files ...{ get ...{ return this._file } set ...{ this._file = value; } } public ThreadDemo1() ...{/**//*Constructor*/} public void Run() ...{ foreach(string strItem in _file) ...{ Console.WriteLine( strItem ); Thread.Sleep(1000); } } } public delegate string GetStrHandler(int index); //定义委托 class ThreadDemo2 ...{ private int _nums; public int Count ...{ get ...{ return this._nums; } set ...{ this._nums = value; } } public event GetStrHandler onPrint; //定义onPrint事件 public ThreadDemo2() ...{/**//*Constructor*/} public void Run() ...{ for (int i = 0; i < this._nums; i++ ) ...{ Console.WriteLine( this.onPrint(i) ); //输出的同时触发事件 Thread.Sleep(1000); ...{ } } /**//** *主窗体类 *// class MainForm: Form ...{ //Some Form Initialization Code //Button button1; //Button button2; //ListView lvItems; //............................................... private ThreadDemo1 td; private ThreadDemo2 dtd; private GetStrHandler GetStr; //方法一,取值 public button1_Click(object sender, EventAvgs e) ...{ td = new ThreadDemo1(); td.Files = new string[lvItems.Itmes.Count]; foreach(ListViewItem Item in lvItems.Items) ...{ int index = Item.index; td.Files[index] = new string(Item.Text); //创建新字符串,避免引用 } Thread myThread = new Thread(new ThreadStart(td.Run)); myThread.Start(); } //方法二,触发事件 public button2_Click(object sender, EventAvgs e) ...{ dtd = new ThreadDemo2(); dtd.onPrint += this.sendmsg(); Thread myThread = new Thread(new ThreadStart(dtd.Run)); myThread.Start(); } private string sendmsg(int index) ...{ string Result = String.Empty; if ( lvItems.InvokeRequired ) //判断是否需要使用Invoke方法,如果当前线程不是控件的创建线程,返回True ...{ GetStr = new GetStrHandler(this.sendmsg); lvItems.Invoke( GetStr, new objcet[] ...{ index } ); } else ...{ Result = lvItems.Items[index].Text; } return Result; } } 将以上代码中的sendmsg方法修改一下,就可以实现跨线程修改控件属性。比如: private string setmsg(int index)
...{ if ( lvItems.InvokeRequired ) //判断是否需要使用Invoke方法,如果当前线程不是控件的创建线程,返回True ...{ GetStr = new GetStrHandler(this.setmsg); lvItems.Invoke( GetStr, new objcet[] ...{ index } ); } else ...{ lvItems.Items[index].Text = "跨线程修改成功"; } return Result; } 这个例子只是简单的使用了委托和事件的基本特性演示了跨线程访问控件的方法。 |
|||||
|
|||||
|
|||||