Следующий шаг: кнопка Show Count
Следующий шаг: кнопка Show Count
Допустим, вы решили проявить творческую фантазию и придать форме вид, показанный на рис. 10.9. Обратите внимание: кнопка Show Count пока недоступна.
Рис. 10.10. Форма с заблокированной кнопкой
Предполагается, что отдельный поток выполняет подсчет и разблокирует недоступную кнопку. Конечно, это можно сделать; более того, такая задача возникает достаточно часто. К сожалению, вы не сможете действовать наиболее очевидным образом — организовать связь вторичного потока с потоком графического интерфейса, сохраняя ссылку на кнопку ShowCount в конструкторе, или даже с использованием стандартного делегата. Иначе говоря, никогда не используйте вариант, приведенный ниже (основные ошибочные строки выделены жирным шрифтом).
Public Class RandomCharacters
Private m_0ata As StringBuilder
Private m_CountDone As Boolean
Private mjength. m_count As Integer
Private m_Button As Windows.Forms.Button
Public Sub New(ByVa1 n As Integer,_
ByVal b As Windows.Forms.Button)
m_length = n - 1
m_Data = New StringBuilder(mJength)
m_Button = b MakeString()
End Sub
Private Sub MakeString()
Dim I As Integer
Dim myRnd As New Random()
For I = 0 To m_length
m_Data.Append(Chr(myRnd.Next(65. 90)))
Next
End Sub
Public Sub StartCount()
GetEes()
End Sub
Private Sub GetEes()
Dim I As Integer
For I = 0 To mjength
If m_Data.Chars(I) = CChar("E") Then
m_count += 1
End If Next
m_CountDone =True
m_Button.Enabled=True
End Sub
Public Readonly
Property GetCount()As Integer
Get
If Not (m_CountDone) Then
Throw New Exception("Count not yet done") Else
Return m_count
End If
End Get
End Property
Public Readonly Property IsDone() As Boolean
Get
Return m_CountDone
End Get
End Property
End Class
Вполне вероятно, что в некоторых случаях этот код будет работать. Тем не менее:
Если вы нарушите эти правила, мы гарантируем, что в ваших многопоточных графических программах будут возникать тонкие, неуловимые ошибки.
Организовать взаимодействие объектов с применением событий тоже не удастся. 06-работник события выполняется в том же потоке, в котором произошел вызов RaiseEvent поэтому события вам не помогут.
И все же здравый смысл подсказывает, что в графических приложениях должны существовать средства модификации элементов из другого потока. В .NET Framework существует поточно-безопасный способ вызова методов приложений GUI из другого потока. Для этой цели используется особый тип делегатов Method Invoker из пространства имен System.Windows. Forms. В следующем фрагменте приведен новый вариант метода GetEes (измененные строки выделены жирным шрифтом):
Private Sub GetEes()
Dim I As Integer
For I = 0 To m_length
If m_Data.Chars(I) = CChar("E")Then
m_count += 1
End If Next
m_CountDone = True Try
Dim mylnvoker As New Methodlnvoker(AddressOf UpDateButton)
myInvoker.Invoke() Catch e As ThreadlnterruptedException
'Неудача
End Try
End Sub
Public Sub UpDateButton()
m_Button.Enabled =True
End Sub
Межпоточные обращения к кнопке осуществляются не напрямую, а через Method Invoker. .NET Framework гарантирует, что этот вариант безопасен по отношению к потокам.