2016-11-05 3 views
1

Прежде всего, прошу прощения, если мой английский плохой, я не являюсь носителем английского языка.Изменение свойства элемента управления через делегата

Я довольно новичок в программировании, и я пытаюсь научить себя VB.NET Я столкнулся с проблемой, пытаясь узнать о делегатах. (см. код ниже)

То, что я пытаюсь выполнить, - это обновить указанное свойство текста элемента управления через поток. Однако, как только я начинаю поток, я получаю ошибку ArgumentException. Я совершенно не знаю, что случилось. У кого-нибудь есть идея, что я сделал здесь неправильно?

Public Class Form1 

Delegate Sub myDelegate1(ByVal s_Name As Control, ByVal s_txt As String) 
Public txtUpdate As New myDelegate1(AddressOf upd_ControlTextProperty) 

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load 
    Label1.Text = vbnullstring 
End Sub 

Private Sub upd_ControlTextProperty(ByVal ControlName As Control, ByVal txt As String) 
    ControlName.Text = txt 
End Sub 

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
    Dim thread1 As New Threading.Thread(AddressOf threadstart) 
    thread1.IsBackground = True 
    thread1.Start() 

End Sub 

Private Sub threadstart() 
     Me.Invoke(Me.txtUpdate, New Object(), {Label1, "This is Label 1"}) 
End Sub 

End Class 
+2

можно передать 3 аргумента, но обратный вызов ожидает только 2. – TheValyreanGroup

+0

hhmmm..This меня смущает, пример из MSDN [ссылка] (https://msdn.microsoft.com/en-us /library/a1hetckb(v=vs.110).aspx) также принимает 3 аргумента, но обратный вызов ожидает только 1. – printf

ответ

2

Как сказал TheValyreanGroup, ваш делегат должен принимать два аргумента, и передать его три:

Me.Invoke(Me.txtUpdate, New Object(), {Label1, "This is Label 1"}) 
      ^-1--------^ ^-2--------^ ^-3-----------------------^ 

Так просто удалить New Object() вещь, и превратить это {Label1, ...} в только строку:

Me.Invoke(Me.txtUpdate, "This is Label 1") 

OK Лучше так.

С другой стороны, то, что вы делаете, не очень полезно.

  • Вы создаете новую тему из вашей темы пользовательского интерфейса.
  • С этой новой резьбой, вы вызываете назад UI тему, и вы остановить тему ...

Помните, что управление может быть обновлен только Thread, который создал форму (UI нить).

Если у вас есть хороший повод, чтобы работать с фоновым потоком, вы можете возобновить свой код на:

Public Class Form1 

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load 
    Label1.Text = vbnullstring 
End Sub 

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
    Label1.Text = "This is Label 1" 
End Sub 

End Class 

UPDATE (с комментариями)

Чтобы сделать его более ясным, здесь является схемой (я взял на https://androidkennel.org/android-networking-tutorial-with-asynctask/, если будут применены какие-либо ограничения, я удалю изображение)

UI Thread and Background Thread

Главного интерфейс резьба используется для вещей:

  • Реагировать на пользовательские события (щелчки, входы ...) и начать фоновые потоки, которые будут делать процесс
  • Update Интерфейс пользователя, когда фоновый поток над или во время задачи.

Когда я говорю, что вы делаете, не полезно, потому что ваш фоновый поток не делает какой-либо обработки, он просто сигнализирует поток пользовательского интерфейса для обновления пользовательского интерфейса ...

+1

Эй, спасибо человеку! Я понимаю, что проще обновить свойство элемента управления с помощью события нажатия кнопки или из самой Формы. Это было просто упражнение для понимания и применения делегатов. На другой ноте, однако, почему бы сказать, что создание нового потока из потока пользовательского интерфейса не полезно? Я имею в виду, где должны быть созданы потоки? Не могли бы вы рассказать? – printf

+1

Нет проблем при запуске нового потока из потока пользовательского интерфейса. Проблема связана с целями нового потока, который предназначен для одновременного запуска двух асинхронных процессов. Если основной целью нового потока является обновление пользовательского интерфейса, то для выполнения обновления будут выполняться непрерывные обратные вызовы в потоке пользовательского интерфейса. Таким образом, выполнение такой операции во втором потоке не является оптимальным, поскольку обновления пользовательского интерфейса могут быть решены одним потоком пользовательского интерфейса. –

+0

@printf обновил мой ответ, чтобы вы могли получить более четкое представление об использовании фоновых потоков –

0

Я хотел бы попробовать этот подход , upd_ControlTextProperty может быть вызван успешно либо из потока пользовательского интерфейса, либо из вашего нового потока.

Public Class Form1 

Delegate Sub myDelegate1(ByVal s_Name As Control, ByVal s_txt As String) 
Public txtUpdate As New myDelegate1(AddressOf upd_ControlTextProperty) 

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load 
    Label1.Text = "" 
End Sub 

Private Sub upd_ControlTextProperty(ByVal ControlName As Control, ByVal txt As String) 
    If Me.InvokeRequired = True Then 
     Me.Invoke(txtUpdate, New Object() {ControlName, txt}) 
    Else 
     ControlName.Text = txt 
    End If 
End Sub 

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
    Dim thread1 As New Threading.Thread(AddressOf threadstart) 
    thread1.IsBackground = True 
    thread1.Start() 
End Sub 

Private Sub threadstart() 
    upd_ControlTextProperty(Label1, "This is Label 1") 
End Sub 

End Class 
Смежные вопросы