Cамоучитель по VB.NET

         

Форма с заблокированной кнопкой




Предполагается, что отдельный поток выполняет подсчет и разблокирует недоступную кнопку. Конечно, это можно сделать; более того, такая задача возникает достаточно часто. К сожалению, вы не сможете действовать наиболее очевидным образом — организовать связь вторичного потока с потоком графического интерфейса, сохраняя ссылку на кнопку 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 гарантирует, что этот вариант безопасен по отношению к потокам.



Содержание раздела