Vb.net 为什么此工作线程/线程没有停止?
我有一个面板,其中有几个组合框和一个按钮来关闭面板。我设置了组合框来填充另一个线程,因为它有许多条目。因此,后台工作程序将启动,一切按预期进行,直到您关闭面板。如果在后台工作程序完成之前关闭面板,则会出现错误。让我解释一下: 我通过启动后台工作程序启动以下过程:Vb.net 为什么此工作线程/线程没有停止?,vb.net,multithreading,backgroundworker,Vb.net,Multithreading,Backgroundworker,我有一个面板,其中有几个组合框和一个按钮来关闭面板。我设置了组合框来填充另一个线程,因为它有许多条目。因此,后台工作程序将启动,一切按预期进行,直到您关闭面板。如果在后台工作程序完成之前关闭面板,则会出现错误。让我解释一下: 我通过启动后台工作程序启动以下过程: get_info.RunWorkerAsync() “关闭”按钮子项如下所示: Private Sub close_everything() ' dispose of the panel that holds the comb
get_info.RunWorkerAsync()
“关闭”按钮子项如下所示:
Private Sub close_everything()
' dispose of the panel that holds the comboboxes
info_panel.dispose()
' tell the background worker to stop working
get_info.CancelAsync()
End Sub
Private Sub getInfo_doWork()
'populate the combo boxes
populate_last_names()
End Sub
Private Sub populate_last_names()
' get the names
get_names()
' since the combobox control is in another thread, I need to use the Invoke method to access it
' put them in the combobox
for a as integer = 0 to last_names.count - 1
last_name_box.Invoke(Sub() last_name_box.Items.Add(last_names(a)))
next
End Sub
我这样设置后台工作人员:
Private Sub close_everything()
' dispose of the panel that holds the comboboxes
info_panel.dispose()
' tell the background worker to stop working
get_info.CancelAsync()
End Sub
Private Sub getInfo_doWork()
'populate the combo boxes
populate_last_names()
End Sub
Private Sub populate_last_names()
' get the names
get_names()
' since the combobox control is in another thread, I need to use the Invoke method to access it
' put them in the combobox
for a as integer = 0 to last_names.count - 1
last_name_box.Invoke(Sub() last_name_box.Items.Add(last_names(a)))
next
End Sub
然后,用于填充姓氏的子例程如下所示:
Private Sub close_everything()
' dispose of the panel that holds the comboboxes
info_panel.dispose()
' tell the background worker to stop working
get_info.CancelAsync()
End Sub
Private Sub getInfo_doWork()
'populate the combo boxes
populate_last_names()
End Sub
Private Sub populate_last_names()
' get the names
get_names()
' since the combobox control is in another thread, I need to use the Invoke method to access it
' put them in the combobox
for a as integer = 0 to last_names.count - 1
last_name_box.Invoke(Sub() last_name_box.Items.Add(last_names(a)))
next
End Sub
当按下close按钮时,我得到一个错误,说明combobox已被释放。因此,我首先添加了一个后台工作人员的检查。因此,我的代码更改为:
' put them in the combobox
for a as integer = 0 to last_names.count - 1
if not(get_info.CancellationPending) then
last_name_box.Invoke(Sub() last_name_box.Items.Add(last_names(a)))
end if
next
但我仍然收到相同的错误,因此我添加了另一个检查,并将代码更改为:
' put them in the combobox
for a as integer = 0 to last_names.count - 1
if not(get_info.CancellationPending) then
if not(last_name_box.IsDisposed) then
last_name_box.Invoke(Sub() last_name_box.Items.Add(last_names(a)))
end if
end if
next
如果我在循环完成之前关闭面板,我仍然会收到一个错误,说明last_name框已被释放
该错误甚至声明last_name_box.IsDisposed的值为TRUE,CancellationPending的值为TRUE。那么,如果它是真的,为什么它要执行下一行呢
如何阻止这种情况发生?首先尝试停止后台工作程序:
Private Sub close_everything()
' tell the background worker to stop working
get_info.CancelAsync()
' dispose of the panel that holds the comboboxes
info_panel.dispose()
End Sub
你的代码构造得很糟糕。您应该做的是在DoWork事件处理程序中获取数据,然后通过e.Result属性将其传递给RunWorkerCompleted事件处理程序。然后,使用在UI线程上执行的RunWorkerCompleted事件处理程序中的数据填充控件
您也不应该将面板隐藏在RunWorkerCompleted事件处理程序之外的任何位置。您从UI线程请求取消,然后在DoWork事件处理程序中实际执行取消。在RunWorkerCompleted事件处理程序中,检查操作是否已取消。如果是这样,您只需隐藏面板,否则您将填充列表。由于我的问题似乎不可能找到可行的答案,我最终切换到带有自动填充的文本框,而不是带有自动填充的组合框。我只是使用组合框,因为自动填充功能,没有意识到文本框可以做同样的事情。在后台工作程序中收集数据,并在主UI中收集数据后分配自动填充的源。我不能完全完成我想要的,所以我决定这样做。仍有一些延迟,但可以控制。我认为错误是因为您试图处理已处理的内容(即问题在于
关闭所有内容)。您能否确认异常出现在哪个范围内?close_everything子项只调用一次。错误出现在我试图向组合框添加项目的行上。具体错误是:无法访问已释放的对象。对象名称:“组合框”。整个问题的出现是因为在同一个线程上向组合框添加27000个名称,而UI会让大多数人将界面挂起太长时间。这就是为什么我需要在另一个线程中实际填充列表。与填充combobox.bulk相比,获取名称的速度更快。您别无选择,只能将名称添加到UI线程上的组合框中,如您自己所示。你认为Invoke做什么?它将方法调用封送到拥有您调用它的控件的线程,即UI线程。您应该做的是调用AddRange一次,而不是在循环中反复添加。事实上,通过在循环中调用Invoke,您将使所有操作花费更长的时间,因为这样做会带来开销。除此之外,一份包含27000项的清单?恐怕这不是一个好的用户体验。我只是想一想——如果在添加条目时组合框不可见,并且当时它没有父项或所有者,那么有没有完成任何消息传递?您可以创建一个combobox实例,向线程发送信号,填充它,返回消息并在主线程中显示它?不知道-从未尝试过:)谢谢Martin,但组合框当时是可见的。我不知道你会怎么做。我现在还在寻找替代品。你为什么还在寻找替代品?您已经知道需要执行的操作。后台工作程序将在close_everything子例程中停止。这就是问题的原因。