WPF异步编程(使用线程)

时间:2019-02-25 22:00:18

标签: xml vb.net multithreading asynchronous async-await

我对异步编程还很陌生,但仍在尝试学习。我有一个应用程序,该应用程序读取巨大的XML文件(大约2GB),然后将其解析为表格。由于XMLreader需要大量时间,因此我需要异步方法。我创建了一个按钮(OnClick事件)异步并使用了任务/等待,但它给我一个错误(也许我没有正确使用它)。然后,在在线阅读后,我编写了以下代码(使用线程)。

Private Sub Parse_Btn_2G_Click(sender As Object, e As RoutedEventArgs) Handles Parse_Btn_2G.Click

        Dim count As ArrayList
        Dim action As Action
        Dim Thread As Thread = New Thread(Sub()
                                              count = CountXML()
                                              action = Sub()
                                                           Status_Txtbox.Text = count(0).ToString() + " Managed Objects in XML"
                                                       End Sub
                                              Me.Dispatcher.Invoke(action)
                                          End Sub)
        Thread.Start()
        Status_Txtbox.Text = "Processing File. Please Wait...."
    End Sub

CountXML是读取XML文件并计算属性的方法。这是用于计数属性的代码。

Private Function CountXML() As ArrayList

        Dim settings As New XmlReaderSettings
        settings.DtdProcessing = DtdProcessing.Ignore
        settings.Async = True
        Dim MONumbers As ArrayList = New ArrayList
        Dim ADCEcount As Integer = 0
        Dim BSCCount As Integer = 0
        Dim BCFCount As Integer = 0
        Dim TRXCount As Integer = 0

        Dim desiredvalue As Boolean = True

        Dim xReader As XmlReader = XmlReader.Create(xml_txtbox_2G.Text, settings)
        Dim ns As XNamespace = XNamespace.Get("raml20.xsd")

        While xReader.Read()
            If xReader.Name <> "managedObject" Then
                xReader.ReadToFollowing("managedObject")
            End If
            If Not xReader.EOF Then
                Dim managedObject As XElement = XElement.ReadFrom(xReader)

                If CType(managedObject.Attribute("class"), String) = "ADCE" Then
                    ADCEcount = ADCEcount + 1
                End If

                If CType(managedObject.Attribute("class"), String) = "BSC" Then
                    BSCCount = BSCCount + 1
                End If

                If CType(managedObject.Attribute("class"), String) = "BCF" Then
                    BCFCount = BCFCount + 1
                End If

                If CType(managedObject.Attribute("class"), String) = "TRX" Then
                    TRXCount = TRXCount + 1
                End If
            End If  
        End While

        MONumbers.Add(ADCEcount)
        MONumbers.Add(BSCCount)
        MONumbers.Add(BCFCount)
        MONumbers.Add(TRXCount) 
        Return MONumbers
    End Function

当我不使用线程或等待/任务代码时,函数CountXML()可以很好地工作,但是一旦使用线程,我就会收到一条错误消息

  

System.InvalidOperationException:'调用线程无法访问   该对象,因为其他线程拥有它。'

我认为这是因为xml_txtbox_2G.Text是UI线程已使用的文本框控件(具有xml文件路径)。有人可以指导如何释放它,或者在读取xml文件时使用异步方法。谢谢

1 个答案:

答案 0 :(得分:0)

我认为您可以通过较小的修改将问题投放到Async / Await中。我尚未测试以下代码,但它与我编写的有效材料相似。

Private Async Sub Parse_Btn_2G_Click(sender As Object, e As RoutedEventArgs) Handles Parse_Btn_2G.Click
    Status_Txtbox.Text = "Processing File. Please Wait...."
    Dim count = Await CountXML
    Status_Txtbox.Text = count(0).ToString() + " Managed Objects in XML"
End Sub

Private Async Function CountXML() As Task(Of ArrayList)
    Dim asTask = Task.Run(Function() CountXMLImpl)
    Return Await asTask
End Function

Private Function CountXMLImpl() As ArrayList
    'Current contents of CountXML.  You might name this and the async version differently if desired.
End Function

如果您想取消进行中的工作,则可以向Task.Run提供取消令牌。以我的经验,这似乎只对排队等待线程的任务有影响,但没有积极处理。我没有研究强制执行中止和取消操作可能需要做的事情;也许正确的做法是将取消令牌作为基础例程的参数,并定期检查令牌是否已请求取消。

Private Async Function CountXML(ByVal cancellationSource as System.Threading.CancellationTokenSource)
    Dim asTask = Task.Run(Function() CountXMLImpl, cancellationSource.Token)
    Return Await asTask
End Function