0

第一次在这里发帖。虽然潜伏了很长时间。我会马上解决的。

我的小项目是一个应用程序,它可以从 craigslist 中删除帖子。抓取后,列表数据将发送到“Form1”中的列表框。我创建了一个工人阶级来处理所有的抓取。当我的类函数“guiAdd()”无法正确填充列表框时,就会出现问题。

鉴于 Form1 确实存在,并且它确实有一个名为“lvsearch”的列表框控件:

这就是我认为问题所在: 类子例程

Private Sub guiAdd(ByVal data As String)
    If Form1.lvsearch.InvokeRequired Then
        Form1.lvsearch.Invoke(New Action(Of String)(AddressOf guiAdd), data)
    Else
        Dim fitem As New ListViewItem
        fitem.Text = data
        'Form1.lvsearch.Items.Add(fitem) <---Original Version
        Form1.lvsearch.Items.Add(New ListViewItem("WTF!!!!")) '<--- Sanity Version
    End If
End Sub

这是完整的课程:

Imports System.Threading
Imports System.Threading.Thread
Imports System.IO
Imports System.Net

Public Class craigsearcher
    Private cURL As String 'Class scope variables preceded by "c"
    Private cSER As Integer





Public Sub New(ByVal fURL As String, Optional ByVal autoStart As Boolean = True)
    Try
        cURL = fURL 'Function scope variables preceded by "f"
        serialGen()
        If autoStart = True Then
            invokeSearch()
        End If
    Catch ex As Exception
        MessageBox.Show(ex.Message)
    End Try
End Sub





Private Sub invokeSearch()
    Dim cTHREAD As New Threading.Thread(AddressOf search)
    cTHREAD.IsBackground = True
    cTHREAD.Start()
End Sub





Private Sub serialGen()
    'Random number to track this threads temp files

    Dim fRND As Double
    Dim fINT As Integer

    Randomize()
    fRND = Rnd() * 1000000000
    fINT = Math.Floor(fRND)
    cSER = fINT.ToString
End Sub






Private Sub search()
    'Class Workflow

    prepData()
    extractData()
    'MessageBox.Show("Debug: End of Thread")
End Sub





Private Sub prepData()
    'WIP: This is just proof of concept currently.
    'Needs revision, but get the job done for now.

    Dim client As New WebClient()
    Dim rawHTML As String = client.DownloadString(New Uri(cURL))


    Dim fo As New StreamWriter(".\temp\" & cSER & ".dat")
    fo.WriteLine(rawHTML)
    fo.Close()
    Thread.Sleep(25)
    Dim fo2 As New StreamReader(".\temp\" & cSER & ".dat")
    Dim fo2str As String = ""
    Do Until fo2.EndOfStream = True
        fo2str = fo2str & Trim(fo2.ReadLine()) & vbCrLf
    Loop
    fo2.Close()
    Thread.Sleep(25)

    System.IO.File.Delete(".\temp\" & cSER & ".dat")

    Dim fo3 As New StreamWriter(".\temp\Prep" & cSER & ".dat")
    fo3.WriteLine(fo2str)
    fo3.Close()
    Thread.Sleep(25)
End Sub





Private Sub extractData()
    'WIP: This is just proof of concept currently.

    Dim fo As New StreamReader(".\temp\Prep" & cSER & ".dat")
    Dim fstr As String = ""

    Do Until fo.EndOfStream = True
        fstr = fo.ReadLine()

        If InStr(fstr, "<p class=") Then 
            'FUTURE LOGIC AND STUFFS SORTED HERE. Regex etc.
            guiAdd(fstr)
        End If

    Loop
End Sub





Public Sub guiAdd(ByVal data As String)
    If Form1.lvsearch.InvokeRequired Then
        Form1.lvsearch.Invoke(New Action(Of String)(AddressOf guiAdd), data)
    Else
        Dim fitem As New ListViewItem
        fitem.Text = data
        'Form1.lvsearch.Items.Add(fitem) <---Original Version
        Form1.lvsearch.Items.Add(New ListViewItem("WTF!!!!")) '<--- Sanity Version
    End If
End Sub

End Class

这是类被实例化的方式:

 Dim worker As New craigsearcher("http://atlanta.craigslist.org/ggg/", True)

所以,这就是我所拥有的一切。我意识到解析代码需要修改/完成。我会解决的。这是在概念验证阶段。正确的数据类型被传递。我只需要一些帮助来理解为什么 addGUI() 不能正常工作。我对多线程的世界并不是特别精通,所以我很高兴我能做到这一点。

我一直以此为指导: http ://www.vbforums.com/showthread.php?682082-Understanding-Multi-Threading-in-VB-Net

4

2 回答 2

0

尝试修改此方法:

Private Sub search()
    'Class Workflow

    prepData()
    extractData()
    'MessageBox.Show("Debug: End of Thread")
End Sub

对此

Private Sub search()
    'Class Workflow

    Thread.QueueUserWorkItem(prepData)
    Thread.QueueUserWorkItem(extractData)
    'MessageBox.Show("Debug: End of Thread")
End Sub

尝试将其放在线程池中。这意味着让第一种方法在第二种方法之前先完成。如果你把它放在一个线程上,它应该是按时间顺序排列的。这可能是因为 extractData() 方法首先完成了它的处理,而不是 prepData() 方法。

希望能帮助到你。

于 2014-05-24T04:05:19.680 回答
0

您是否在没有单独的工作线程/线程的情况下对此进行了测试?

这应该是你的形式,而不是你的工人阶级/线程:

如果你愿意,你可以把它放在 listview 控件中,只要确保你可以从你的其他类中引用它。

Private Delegate Sub invokeGuiAdd(ByVal data As String)
Public Sub guiAdd(ByVal data As String)
    If InvokeRequired Then
        'Form1.lvsearch.Invoke(New Action(Of String)(AddressOf guiAdd), data)
        Invoke(New invokeGuiAdd(AddressOf guiAdd), New Object() {data})
    Else
        Dim fitem As New ListViewItem
        fitem.Text = data
        'Form1.lvsearch.Items.Add(fitem) <---Original Version
        lvsearch.Items.Add(New ListViewItem("WTF!!!!")) '<--- Sanity Version
    End If
End Sub

Form1.guiAdd(fstr)

哦,作为旁注,事件是委托,因此您可以使用事件来代替。

于 2014-05-24T04:13:18.957 回答