如果对多线程基础不太熟悉建议看之前先去看http://tieba.baidu.com/p/2287683723
首先还是开始对一些概念进行总结
首先从个例子开始,如下代码
Private Sub ButClick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Do
Loop
End Sub
这段代码在Button1按下去同时会失去响应,界面卡住
对这个代码进行修改添加一条语句
Private Sub ButClick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Do
Application.DoEvents()
Loop
End Sub
这里的Application.DoEvents可以让窗体优先处理当前窗体信息列表中的其他信息,这样窗体就可以响应重绘,拖动事件了
在窗体中添加一个ListBox控件,目的通过这个循环在ListBox中动态显示字母A-F中的随即字母
Private Sub ButClick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim rand As New Random
Do
Me.ListBox1.Items.Add(Chr(rand.Next(65, 90)))
Application.DoEvents()
Threading.Thread.Sleep(1000)
Loop
End Sub
这里的做法并不是可取的,只是为了说明效果,可见窗体中ListBOX里随即动态的添加字母
这里的UI线程其实从没有休息过一直在工作,对资源损耗非常大,现在改变代码的组织形式,在后台线程定时向UI线程发送请求来完成任务,并且5个字母,每阁1秒发一次
代码如下
Private Delegate Sub threadwork() '后台执行的任务委托
Private Delegate Sub play(ByVal str As String) ’更新窗体ListBox1控件的委托
Private Sub th_work()
Dim list As New System.Text.StringBuilder
Dim rand As New Random
Do
list.Append(Chr(rand.Next(65, 90)))
If list.Length = 5 Then
Me.Dispaly(list.ToString)'这里请处理,这里是副线程访问方法
list.Remove(0, list.Length)
Threading.Thread.Sleep(1000)
End If
Loop
End Sub
Private Sub Dispaly(ByVal str As String)
If Me.InvokeRequired Then
Dim playsub As New play(AddressOf Me.Dispaly)
Me.BeginInvoke(playsub, str) '这里请注意,这里副线程和主线程将要同时执行
Else
Me.ListBox1.Items.Add(str & "*")
End If
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Me.ListBox1.Items.Clear()
Dim work As New threadwork(AddressOf Me.th_work)
work.BeginInvoke(Nothing, Nothing)’异步请求
End Sub
代码也是相当简单,不过这里可以得到一个非常好的UI体验,并且UI线程除了响应异步请求,其他时间都是空闲的有足够时间来完成重绘事件.
接下来我们来具体说下事件
先来声明一个类
Public Class EventA
Private events As New List(Of HandEvent1)
Public Event Evet_1(ByVal obj As Object)
Public Delegate Sub HandEvent1(ByVal obj As Object)
Public Custom Event Evet_2 As HandEvent1
AddHandler(ByVal value As HandEvent1)
events.Add(value)
End AddHandler
RemoveHandler(ByVal value As HandEvent1)
events.Remove(value)
End RemoveHandler
RaiseEvent()
For Each handle As HandEvent1 In events
handle.BeginInvoke(Nothing, Nothing)
Next
End RaiseEvent
End Event
Public Sub EventStart()
RaiseEvent Evet_1(Nothing)
RaiseEvent Evet_2
End Sub
End Class
这里的代码很简单,声明了一类EventA,并且在其中用2种方法声明了事件Evet_1和Evet_2
我们这里声明的List(Of HandEvent1),HandEvent1只是用来处理这Evet_2的委托,事实上现在VB在事件处理上参数列表已经非常宽松,我们可以用任意参数列表的方法来自由响应事件
我们在窗体中声明
Private WithEvents eve As EventA
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
eve = New EventA
eve.EventStart()
End Sub
Private Sub eve_Evet_1() Handles eve.Evet_1, eve.Evet_2
Static n As Integer
n += 1
Me.ListBox1.Items.Clear()
End Sub
测试代码,你按Buttoun之后你会发现出现错误,提示为线程间操作无效: 从不是创建控件“ListBox1”的线程访问它。这里如果你用断点追踪的话,会发现这个eve_Evet_1方法被执行了2次,因为=2,一次是UI线程,一次次线程池里的线程,由于不是UI线程所以出错
这里说明没参数的方法可以响应显示声明带参数委托的事件,但是有个条件那就是必须用
WithEvents 和Handles关键字的组合才能实现对委托方法的参数形式的宽容
如果用AddHandler eve.Evet_2, AddressOf Me.eve_Evet_1,或出错误,这里委托和方法不匹配
总结:
1、线程之间的事件只是线程之间同步异步请求
2、对象事件可以用任意参数方法来响应,但必须使用WithEvents 和Handles
3、只有Control类才具备线程亲和性,对象事件不具备这样的特性
4、对象事件的处理,我们可以用不同的线程去去异步处理,这样就可以防止事件处理列表的事件响应方法的同步阻塞
5、请多多注意Thread.Sleep方法和Application.DoEvents方法
多线程技术是一种代码流控制技术,是编程的基础,希望本文能给予大家一些基础帮助,
祝大家快乐^^
首先还是开始对一些概念进行总结
首先从个例子开始,如下代码
Private Sub ButClick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Do
Loop
End Sub
这段代码在Button1按下去同时会失去响应,界面卡住
对这个代码进行修改添加一条语句
Private Sub ButClick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Do
Application.DoEvents()
Loop
End Sub
这里的Application.DoEvents可以让窗体优先处理当前窗体信息列表中的其他信息,这样窗体就可以响应重绘,拖动事件了
在窗体中添加一个ListBox控件,目的通过这个循环在ListBox中动态显示字母A-F中的随即字母
Private Sub ButClick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim rand As New Random
Do
Me.ListBox1.Items.Add(Chr(rand.Next(65, 90)))
Application.DoEvents()
Threading.Thread.Sleep(1000)
Loop
End Sub
这里的做法并不是可取的,只是为了说明效果,可见窗体中ListBOX里随即动态的添加字母
这里的UI线程其实从没有休息过一直在工作,对资源损耗非常大,现在改变代码的组织形式,在后台线程定时向UI线程发送请求来完成任务,并且5个字母,每阁1秒发一次
代码如下
Private Delegate Sub threadwork() '后台执行的任务委托
Private Delegate Sub play(ByVal str As String) ’更新窗体ListBox1控件的委托
Private Sub th_work()
Dim list As New System.Text.StringBuilder
Dim rand As New Random
Do
list.Append(Chr(rand.Next(65, 90)))
If list.Length = 5 Then
Me.Dispaly(list.ToString)'这里请处理,这里是副线程访问方法
list.Remove(0, list.Length)
Threading.Thread.Sleep(1000)
End If
Loop
End Sub
Private Sub Dispaly(ByVal str As String)
If Me.InvokeRequired Then
Dim playsub As New play(AddressOf Me.Dispaly)
Me.BeginInvoke(playsub, str) '这里请注意,这里副线程和主线程将要同时执行
Else
Me.ListBox1.Items.Add(str & "*")
End If
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Me.ListBox1.Items.Clear()
Dim work As New threadwork(AddressOf Me.th_work)
work.BeginInvoke(Nothing, Nothing)’异步请求
End Sub
代码也是相当简单,不过这里可以得到一个非常好的UI体验,并且UI线程除了响应异步请求,其他时间都是空闲的有足够时间来完成重绘事件.
接下来我们来具体说下事件
先来声明一个类
Public Class EventA
Private events As New List(Of HandEvent1)
Public Event Evet_1(ByVal obj As Object)
Public Delegate Sub HandEvent1(ByVal obj As Object)
Public Custom Event Evet_2 As HandEvent1
AddHandler(ByVal value As HandEvent1)
events.Add(value)
End AddHandler
RemoveHandler(ByVal value As HandEvent1)
events.Remove(value)
End RemoveHandler
RaiseEvent()
For Each handle As HandEvent1 In events
handle.BeginInvoke(Nothing, Nothing)
Next
End RaiseEvent
End Event
Public Sub EventStart()
RaiseEvent Evet_1(Nothing)
RaiseEvent Evet_2
End Sub
End Class
这里的代码很简单,声明了一类EventA,并且在其中用2种方法声明了事件Evet_1和Evet_2
我们这里声明的List(Of HandEvent1),HandEvent1只是用来处理这Evet_2的委托,事实上现在VB在事件处理上参数列表已经非常宽松,我们可以用任意参数列表的方法来自由响应事件
我们在窗体中声明
Private WithEvents eve As EventA
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
eve = New EventA
eve.EventStart()
End Sub
Private Sub eve_Evet_1() Handles eve.Evet_1, eve.Evet_2
Static n As Integer
n += 1
Me.ListBox1.Items.Clear()
End Sub
测试代码,你按Buttoun之后你会发现出现错误,提示为线程间操作无效: 从不是创建控件“ListBox1”的线程访问它。这里如果你用断点追踪的话,会发现这个eve_Evet_1方法被执行了2次,因为=2,一次是UI线程,一次次线程池里的线程,由于不是UI线程所以出错
这里说明没参数的方法可以响应显示声明带参数委托的事件,但是有个条件那就是必须用
WithEvents 和Handles关键字的组合才能实现对委托方法的参数形式的宽容
如果用AddHandler eve.Evet_2, AddressOf Me.eve_Evet_1,或出错误,这里委托和方法不匹配
总结:
1、线程之间的事件只是线程之间同步异步请求
2、对象事件可以用任意参数方法来响应,但必须使用WithEvents 和Handles
3、只有Control类才具备线程亲和性,对象事件不具备这样的特性
4、对象事件的处理,我们可以用不同的线程去去异步处理,这样就可以防止事件处理列表的事件响应方法的同步阻塞
5、请多多注意Thread.Sleep方法和Application.DoEvents方法
多线程技术是一种代码流控制技术,是编程的基础,希望本文能给予大家一些基础帮助,
祝大家快乐^^