多线程,一个古老的话题,今天我来聊下最基本的线程,UI线程和后台线程。
在后台线程中直接操作UI控件会出现异常(线程间操作无效:从不是创建控件“XX”的线程访问它)。怎么解决这个问题那?关键点在代理和InvokeRequired属性,Winform的UI(窗口)代码如下:
using
System;
using
System.Collections.Generic;
using
System.ComponentModel;
using
System.Data;
using
System.Drawing;
using
System.Text;
using
System.Windows.Forms;
using
LandpyLibrary;
using
LandpyCommon;
namespace
LandpyWindowsForm
{
public
partial
class
MainForm : Form, IFormWorkThread
{
public
MainForm()
{
InitializeComponent();
cdObj
=
SetTime;
}
private
delegate
void
ControlDelegate(
string
time);
private
WorkThread wtObj;
ControlDelegate cdObj;
private
void
SetTime(
string
time)
{
lblTime.Text
=
time;
}
public
void
ShowTime(
string
time)
{
if
(lblTime.InvokeRequired)
{
Invoke(cdObj, time);
}
else
{
SetTime(time);
}
}
private
void
btnStart_Click(
object
sender, EventArgs e)
{
wtObj
=
new
WorkThread(
this
);
wtObj.StartShowTime();
}
private
void
btnEnd_Click(
object
sender, EventArgs e)
{
if
(wtObj
!=
null
)
{
wtObj.EndShowTime();
}
}
private
void
MainForm_FormClosing(
object
sender, FormClosingEventArgs e)
{
if
(wtObj
!=
null
)
{
wtObj.EndShowTime();
}
}
}
}
为了能在后台线程中操作UI线程,我们的MainForm继承了公共接口IFormWorkThread,接口定义如下:
using System;
using System.Collections.Generic;
using System.Text;
namespace LandpyCommon
{
public interface IFormWorkThread
{
void ShowTime(string time);
}
}
该接口放在一个独立的Dll中,UI线程和后台线程也均处于不同的程序集中,它们均引用了该接口的Dll。
后台线程类如下:
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.Threading;
using
LandpyCommon;
namespace
LandpyLibrary
{
public
class
WorkThread
{
private
IFormWorkThread _formWorkThread;
private
Thread thread;
public
WorkThread(IFormWorkThread formWorkThread)
{
_formWorkThread
=
formWorkThread;
}
public
void
Deal()
{
while
(
true
)
{
Thread.Sleep(
1000
);
_formWorkThread.ShowTime(DateTime.Now.ToString());
}
}
public
void
StartShowTime()
{
thread
=
new
Thread(
new
ThreadStart(Deal));
thread.Name
=
"
TimeThread
"
;
thread.Start();
}
public
void
EndShowTime()
{
thread.Abort();
}
}
}
其实报异常是因为多线程操作UI控件是非安全的,MS提供了解决方案,关键代码如下:
public MainForm()
{
InitializeComponent();
cdObj = SetTime;
}
private delegate void ControlDelegate(string time);
ControlDelegate cdObj;
private void SetTime(string time)
{
lblTime.Text = time;
}
public void ShowTime(string time)
{
if (lblTime.InvokeRequired)
{
Invoke(cdObj, time);
}
else
{
SetTime(time);
}
}
通过代理和InvokeRequired属性解决了这个问题。