Асинхронное программирование WPF (с использованием потоков) - PullRequest
0 голосов
/ 26 февраля 2019

Я довольно новичок в асинхронном программировании и все еще пытаюсь выучить его.У меня есть приложение, которое читает огромный XML-файл (около 2 ГБ) и затем анализирует его в таблицах.Поскольку 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 () прекрасно работает, когда я не использую потоки или код Await / Task, но как только я использую потоки, я получаю сообщение об ошибке

System.InvalidOperationException: 'Вызывающий поток не может получить доступ к этому объекту, поскольку он принадлежит другому потоку.'

Я думаю, это потому, что xml_txtbox_2G.Text является элементом управления textbox (с путем к файлу xml), которыйуже используется UI Thread.Может кто-нибудь, пожалуйста, руководство, как выпустить его или использовать асинхронный метод при чтении файла XML.Спасибо

1 Ответ

0 голосов
/ 26 февраля 2019

Я думаю, что вы можете преобразовать вашу проблему в 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
...