目标:如题
问题说明:
一、进程与线程
process和Thread,一个程序运行,就形成了一个进程(对操作系统而言),该程序如果有一个main窗口,这个窗口就是主线程。
问题是:这个主线程到底包括哪些内容?
我试验下来,认为包括当前窗体和一起被加载的各个公共模块。
二、为啥要开出一个线程
代码默认运行在主线程上,如果复杂度较大,程序主界面会出现无响应的假死状态。而开出一个新的线程可以解决这个问题。
线程会在主程序的幕后,静默的运行,那么问题来了,如何知道这个新开的线程,运行进度情况?
三、线程在主程序的进度显示
我们在主程序窗体运行在一个主线程上,新开的线程如果直接设置窗体控件的属性,属于跨线程操作。
我们需要用到“委托”,如下:声明一个委托
Public Delegate Sub deal()
这样一个名称为deal的委托就被声明
委托相当于代理人,下面还要有具体办事的人,就是具体操作部分,通过一个委托可以指向多个具体办事人。
如下:我们搭一个具体办事人,实际上可以搭很多。
Public Sub dealinfo()
'/// 填入实际需要实现的内容,就是操作控件属性的部分。
End Sub
一旦线程中需要用到dealinfo的操作部分,就可以如下提出:
Dim dh As deal = New deal(AddressOf dealinfo)
If Me.InvokeRequired Then Me.Invoke(dh)
dh = Nothing
四、如何在自定义类中实现这样的过程?
自定义类一般也是要在主线程中被实例化,所以,自定义类中的复杂操作,有新开线程的必要。
问题是:我们如何在自定类中的新开线程内实现上述过程?
方案:
一、描述
在自定义类中,通过事件抛出,有主窗体捕捉该事件,通知主窗体的委托人,实现具体操作。
二、测试代码
'自定义一个类test,模拟进度条,提供四个数据接口,最大值,数值,可见性和提示文字。
Imports System.Threading
Public Class test
Public Event barMessage(ByVal sender As test, ByVal e As EventArgs)
Private t As Thread
Private bar_type As Integer
Private bar_visible As Boolean
Private bar_max As Integer
Private bar_num As Integer
Private bar_Str As String
Public Property infoType As Integer
Get
Return bar_type
End Get
Set(value As Integer)
bar_type = value
End Set
End Property
Public Property visible As Boolean 'infotype:1
Get
Return bar_visible
End Get
Set(value As Boolean)
bar_visible = value
End Set
End Property
Public Property max As Integer 'infotype:2
Get
Return bar_max
End Get
Set(value As Integer)
bar_max = value
End Set
End Property
Public Property num As Integer
Get
Return bar_num
End Get
Set(value As Integer)
bar_num = value
End Set
End Property
Public Property infoStr As String
Get
Return bar_Str
End Get
Set(value As String)
bar_Str = value
End Set
End Property
Public Sub New()
bar_type = 0
bar_max = 0
bar_num = 0
bar_Str = ""
bar_visible = False
End Sub
Private Sub sendinfo(ByVal i As Integer)
bar_type = i
RaiseEvent barMessage(Me, New System.EventArgs())
End Sub
Public Sub dowork()
bar_visible = True
bar_max = 100
bar_num = 0
bar_Str = ""
sendinfo(1)
t = New Thread(AddressOf mydo)
t.Start()
End Sub
Private Sub mydo()
Dim i As Integer
For i = 1 To 100
bar_num = i
bar_Str = "这是第" & i & "条记录"
sendinfo(3)
Thread.Sleep(50)
Next
bar_visible = False
sendinfo(1)
Try
t.Abort()
Catch ex As ThreadAbortException
Thread.ResetAbort()
End Try
End Sub
End Class
在主窗体,放置一个按钮执行自定类中的dowork方法,一个进度条和一个标签显示进度提示。
主窗体的委托实现代码
Imports System.Threading
Public Class Form1
Private myt As test
Private WithEvents my_event As test
Public Delegate Sub deal()
Public Sub dealinfo()
Dim n As Integer = myt.infoType
If n > 0 Then
If n = 1 Or n = 2 Then
Me.ProgressBar1.Visible = myt.visible
Me.ProgressBar1.Maximum = myt.max
Me.ProgressBar1.Value = myt.num
Me.Label1.Visible = myt.visible
Me.Label1.Text = myt.infoStr
Else
Me.ProgressBar1.Value = myt.num
Me.Label1.Text = myt.infoStr
End If
End If
End Sub
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
myt = New test
my_event = myt
End Sub
Private Sub test_myEvent(ByVal sender As test, ByVal e As System.EventArgs) Handles my_event.barMessage
Dim dh As deal = New deal(AddressOf dealinfo)
If Me.InvokeRequired Then Me.Invoke(dh)
dh = Nothing
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
myt.dowork()
End Sub
End Class
这段代码有个非常有趣的Bug,就是主窗体点击按钮后,并没有显示!呵呵
将自定义类代码红色部分,剪切到线程指向函数mydo的开头部分即可,值得玩味!