从vb.net中的多个线程更新列表视图

时间:2014-11-17 09:24:47

标签: vb.net multithreading listview

我有一个程序,我希望使用多线程填充列表视图。

但我有一个问题,即ui线程无法足够快地更新listview。

当它运行checkWishList子时,我得到listview1.Items.count = 0

我尝试使用task.waitall(tasks)执行任务,我尝试使用Task.Factory.ContinueWhenAll,但是它也运行在一个单独的线程中,所以我在尝试更新它时遇到错误。

我唯一能做的就是

Do Until (tasks(0).Status = 5 And tasks(0).Status = 5)
Application.DoEvents()
Loop

然而,这似乎是一个非常糟糕的解决方案而不是真正的修复。

所以我的问题是,在ui线程完成更新之前,有没有办法等待运行checkWishList(),或者我可以让Task.Factory.ContinueWhenAll在ui线程中运行吗?

或者我应该让线程填充listviewitems列表,而不是使用invoke调用uithread来添加项目,然后让listview连接到该数据源?那会让ui线程更新更快吗?

或者在列表上运行foreach并将它们从ui线程添加到listview中?

将会有大约30-50条记录显示,但搜索这些记录需要花费时间,所以这就是我希望它在多个线程中完成的原因。

当然,我可以在添加listviewitem之前获得checkWishList数据库查询并直接设置颜色,但是因为我希望其他函数调用此子也意味着我必须在多个地方使用相同的代码,未来的更新/更改更有问题。

我正在使用.net framework 4.5。

Private Delegate Sub ListViewAddItem_delegate(ByVal Col1 As String, ByVal Col2 As String, ByVal Col3 As String, ByVal Col4 As String, ByVal Col5 As String, ByVal col6 As String, ByVal col7 As String, ByVal col8 As String)
Private Sub ListViewAddItem(ByVal Col1 As String, ByVal Col2 As String, ByVal Col3 As String, ByVal Col4 As String, ByVal Col5 As String, ByVal col6 As String, ByVal col7 As String, ByVal col8 As String)
    If Me.listview1.InvokeRequired Then
        Dim d As New ListViewAddItem_delegate(AddressOf ListViewAddItem)
        Me.listview1.BeginInvoke(d, {Col1, Col2, Col3, Col4, Col5, col6, col7, col8})
    Else
        listview1.Items.Add(New ListViewItem(New String() {Col1, Col2, Col3, Col4, Col5, col6, col7, col8}))
    End If
End Sub


Private Sub search()
    listview1.Items.Clear()

    'Dim tasks = New Task(1) {}
    'For i As Integer = 0 To 1
            'if i = 0 then
                           'tasks(i) = Task.Run(AddressOf doSearch)
    'elseif i = 1 then
                            'tasks(i) = Task.Run(AddressOf doOtherSearch)
    'end if
    'Next
    'Task.Factory.ContinueWhenAll(tasks, Sub()
    '                                        Debug.Print("all threads done")
    '                                    End Sub)
    'Do Until (tasks(0).Status = 5 And tasks(0).Status = 5)
    '    Application.DoEvents()
    'Loop
    'Task.WaitAll(tasks)


    Parallel.For(0, 3, Sub(i)
    if i = 0 then
                           doSearch()
    elseif i = 1 then
                            doOtherSearch()
    end if
                               End Sub)
    checkWishlist()
End Sub


    Public Sub checkWishlist()
    For Each lvi As ListViewItem In listview1.Items
        thisSelectCommand.CommandText = "SELECT * FROM wishlist WHERE ID='" & lvi.SubItems(6).Text & "'"
        reader = thisSelectCommand.ExecuteReader
        If reader.HasRows = True Then
            lvi.ForeColor = Color.Red
        Else
            lvi.ForeColor = Color.Black
        End If
        reader.Close()
    Next
End Sub


public sub doSearch()
for i as integer = 0 to 100
ListViewAddItem("Col1", "Col2", "Col3", "Col4", "Col5", "Col6", "Col7", "Col8")
next
End sub

public sub doOtherSearch()
for i as integer = 0 to 100
ListViewAddItem("Col1", "Col2", "Col3", "Col4", "Col5", "Col6", "Col7", "Col8")
next
End sub

1 个答案:

答案 0 :(得分:0)

您可以使用后台工作人员等待每个任务完成,然后再调用下一个任务:

Private worker_1 As new BackgroundWorker()
Private worker_2 As new BackgroundWorker()

AddHandler worker_1.DoWork, AddressOf worker_1_DoWork
AddHandler worker_1.RunWorkerCompleted, AddressOf worker_1_RunWorkerCompleted
AddHandler worker_2.DoWork, AddressOf worker_2_DoWork
AddHandler worker_2.RunWorkerCompleted, AddressOf worker_2_RunWorkerCompleted

' call the first task
worker_1.RunWorkerAsync()

Public Sub worker_1_DoWork() 
 ' do something here
End Sub

Public Sub worker_1_RunWorkerCompleted
  ' call the next task only after the first task is complete
  worker_2.RunWorkerAsync()
End Sub

Public Sub worker_2_DoWork() 
 ' do something here
End Sub

Public Sub worker_2_RunWorkerCompleted
  ' call the next task
  ' and so on
End Sub