【问题标题】:Update listview from multiple threads in vb.net从 vb.net 中的多个线程更新列表视图
【发布时间】:2014-11-17 09:24:47
【问题描述】:

我有一个程序,我想在其中使用多线程填充列表视图。

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

当它运行 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

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

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

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

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

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

当然,我可以在添加 listviewitem 之前先进行 checkWishList DB 查询并立即设置颜色,但是由于我希望其他函数也调用此子函数,这意味着我必须在多个地方使用相同的代码,这使得未来的更新/更改更成问题。

我正在使用 .net 框架 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

【问题讨论】:

  • 在单独的线程(或任务等)中运行查询,然后将它们添加到主线程的列表视图中。
  • 你的意思是我应该在任务中运行她的 sql 查询并在使用“ListViewAddItem”之前设置前景色还是?
  • 您可以使用 SYNCLOCK 但这只会减慢您的速度。但它会起作用。

标签: vb.net multithreading listview


【解决方案1】:

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

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

【讨论】:

  • 这不会和 Task.Factory.ContinueWhenAll 基本相同吗?还是 runWorkerCompleted 在主线程(ui 线程)中运行?问题是我希望工人 1 和 2 并行运行,然后检查愿望清单。所以并行for循环会做我正在寻找的东西,因为它在继续之前等待所有线程完成。但是,如果我正确理解委托/调用子“队列”UI 更新,所以 checkWishlist 在 ui 有时间将所有项目添加到列表视图之前完成。
  • 如果您在主线程中运行的两个项目之间存在竞争条件,那么您需要通过等待其中一个完成来考虑所有情况。如果这意味着将它们放在单独的线程中,那么也许您应该考虑这一点。要回答您的问题,是的,runWorkerCompleted 在主线程中运行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多