Иллюстрированный самоучитель по VB.NET

       

Следующий шаг: кнопка 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 гарантирует, что этот вариант безопасен по отношению к потокам.


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