如何将进度报告从内部功能传递给主要功能?

How to pass progress reports from inner function to main function?

我目前正在尝试将进度(使用 Iprogress 和 Progress)从内部函数传递到主函数。内部功能完成后一切正常。但是,我 retrieving/downloading 一些数据使用 EBay 的 API 的(EBay 的查找服务是 returns 数据以 XML 格式的休息服务)并且需要通过进度报告在 XML 数据 retrieved/data 处理的下载过程中,从内部函数到主函数。

这是主函数的代码(有点开始超载了,但你知道发生了什么事。评论是为了理智。):

 Private Property a As Integer
        Get
            Return a_value
        End Get
        Set(value As Integer)
            a_value = value
            ' ReportProgress(value, Nothing)
        End Set
    End Property
    Private a_value As Integer
Public Async Function EvaluateItem(item As List(Of ItemInfo), evalprogress As IProgress(Of Integer), Optional ManualEvaluation As Boolean = False) As Task(Of List(Of EvaluationInfo))
    Dim notevaluatedcount As Integer = 0
    Dim iteminfo1 As ItemInfo = New ItemInfo
    Dim tmpiteminfo As List(Of ItemInfo) = New List(Of ItemInfo)
    Dim tmpiteminfo2 As List(Of ItemInfo) = New List(Of ItemInfo)
    Dim pricefunctions As ItemValuation = New ItemValuation
    Dim tmpevalinfo As EvaluationInfo = New EvaluationInfo
    Dim itemevalresultarr As List(Of EvaluationInfo) = New List(Of EvaluationInfo)
    Dim mode As Double
    Dim avg As Double
    Dim min As Double
    Dim max As Double
    Dim standarddev As Double
    Dim pricearr() As Double
    Dim autoitem As List(Of EvaluationInfo) = New List(Of EvaluationInfo)
    Dim itemse As New ItemInformation
    ' Dim itemsnoteval As New ItemInformation
    ' itemseval.itemsevaluated = New List(Of String)
    ' itemsnoteval.notevaluated = New List(Of String)
    Dim tmpnoteval As List(Of ItemInfo) = New List(Of ItemInfo)

    Dim ran As Boolean
    'sort and store item condition information in evaluation table in database or by item.sort
    If item.Count > 1 And ManualEvaluation = True Then
        tmpiteminfo = SortByName(item)
        Await ClearEvalTable()
        tmpiteminfo2 = SortByCondition(tmpiteminfo)
        If CoreApplication.MainView.CoreWindow.Dispatcher.HasThreadAccess Then
            Await Task.Run(Function()

                               'Await Task.Delay(1000)
                               If evalprogress IsNot Nothing Then
                                   'ReportProgress(4, Nothing)
                                   evalprogress.Report(4)
                                   evalprogress.Report(5)
                               End If
                               ' tempCount += 1

                               Return 5
                           End Function)
        ElseIf CoreApplication.MainView.CoreWindow.Dispatcher.HasThreadAccess = False Then
            Await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Function()

                                                                                                             'Await Task.Delay(1000)
                                                                                                             If evalprogress IsNot Nothing Then
                                                                                                                 evalprogress.Report(4)
                                                                                                                 evalprogress.Report(5)
                                                                                                             End If
                                                                                                             ' tempCount += 1

                                                                                                             Return 5
                                                                                                         End Function)

        End If
        'evalprogress.Report(5)
        ' MsgBox("condition count:" + tmpiteminfo2.Count.ToString)
    ElseIf item.Count > 1 And ManualEvaluation = False Then
        'do nothing
    ElseIf item.Count = 1 And ManualEvaluation = True Then
        'change this code to perform manual evaluation on one item.
        'tmpiteminfo.Add(item.Item(0))
    End If
    ReDim pricearr(item.Count)

    If ManualEvaluation Then
        If ran = False Then
            Dim count As Integer
            For Each d As ItemInfo In tmpiteminfo
                count = count + 1
                If ItemValidation.ContainsValidCharacters(d.name) And ItemValidation.IsDouble(d.price) Then
                    'decide whether to manually evaluate the item or automatically evaluate it.
                    Log("Item name: " + d.name + " price #: " + d.price.ToString)
                Else
                    Log("Item: " + d.name + " has invalid characters in its name. It will not be evaluated. Please remove the invalid characters to have the item evaluated." + "The item price may not be an integer. please fix this too (if applicable)")
                    iteminfo1.name = d.name
                    iteminfo1.price = 0
                    iteminfo1.evaluationSource = d.evaluationSource
                    iteminfo1.damaged = "NO"
                    iteminfo1.aquisitiondate = "1/1/1111"
                    iteminfo1.itempicture = Nothing
                    ' tmpnoteval.Add(iteminfo1)
                    tmpevalinfo.currentItem = iteminfo1.name
                    tmpevalinfo.evaluated = False
                    tmpevalinfo.evaluationcondition = d.itemcondition
                    itemevalresultarr.Add(tmpevalinfo)
                    '  tmpnoteval.Add(iteminfo1)
                    notevaluatedcount += 1
                End If
                Select Case d.itemcondition
                    Case Is = ItemCondition.Broken
                        broken.Add(d.price)
                    Case Is = ItemCondition.LooksLikeNew
                        Lookslikenew.Add(d.price)
                        'MsgBox("Looks like new price:" + d.price.ToString)
                    Case Is = ItemCondition.SomewhatUsed
                        somewhatused.Add(d.price)
                        '  MsgBox("Somewhat Used price:" + d.price.ToString)
                    Case Is = ItemCondition.SomeDamage
                        damaged.Add(d.price)
                End Select
            Next
            ran = True
        End If

    Else
        'Automatically evaluate item using different retailers i.e. Amazon, E-Bay, etc.
        'use grabfromonlinesource multiple times to grab from each evaluation source used.
        Dim tmpevalitem As Task(Of List(Of EvaluationInfo))

        For i = 0 To item.Count - 1
            'does once for each item 
            'need to split it into conditions inside of grabfromonlinesource
            If ItemValidation.ContainsValidCharacters(item.Item(i).name) Then

                '  evalprogress = New Progress(Of Integer)(Function(value) InlineAssignHelper(value, a))
                If CoreApplication.MainView.CoreWindow.Dispatcher.HasThreadAccess Then
                    Await Task.Run(Function()

                                       'Await Task.Delay(1000)
                                       If evalprogress IsNot Nothing Then
                                           ' ReportProgress(10, Nothing)
                                           evalprogress.Report(10)
                                           ReportProgress(10, Nothing)
                                       End If
                                       ' tempCount += 1

                                       Return 10
                                   End Function)
                ElseIf CoreApplication.MainView.CoreWindow.Dispatcher.HasThreadAccess = False Then
                    Await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Function()

                                                                                                                     'Await Task.Delay(1000)
                                                                                                                     If evalprogress IsNot Nothing Then
                                                                                                                         evalprogress.Report(10)
                                                                                                                     End If
                                                                                                                     ' tempCount += 1

                                                                                                                     Return 10
                                                                                                                 End Function)

                End If

                tmpevalitem = GrabFromOnlineSource(item.Item(i).name, item.Item(i).evaluationSource, New Progress(Of Integer)(Function(value) InlineAssignHelper(a, value)))
                tmpevalitem.Wait()
                If CoreApplication.MainView.CoreWindow.Dispatcher.HasThreadAccess Then
                    Await Task.Run(Function()

                                       'Await Task.Delay(1000)
                                       If evalprogress IsNot Nothing Then
                                           ' ReportProgress(70, Nothing)
                                           evalprogress.Report(70)
                                       End If
                                       ' tempCount += 1

                                       Return 70
                                   End Function)
                ElseIf CoreApplication.MainView.CoreWindow.Dispatcher.HasThreadAccess = False Then
                    Await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Function()

                                                                                                                     'Await Task.Delay(1000)
                                                                                                                     If evalprogress IsNot Nothing Then
                                                                                                                         'evalprogress.Report(70)
                                                                                                                     End If
                                                                                                                     ' tempCount += 1

                                                                                                                     Return 70
                                                                                                                 End Function)

                End If
                ' ItemValuation.tmpProgressIndicator.Report(60)


                If tmpevalitem.Result IsNot Nothing Then
                    autoitem.AddRange(tmpevalitem.Result)
                Else
                    Continue For
                End If
            Else
                Dim tmpevalinfoauto As EvaluationInfo
                tmpevalinfoauto.currentItem = item.Item(i).name
                tmpevalinfoauto.evaluationcondition = item.Item(i).itemcondition
                autoitem.Add(tmpevalinfoauto)
            End If
        Next i
        autoitem.Add(Nothing) 'use nothing as an indicator of a new item.
    End If

    If ManualEvaluation Then
        Dim done(4) As Boolean
        done(0) = False
        done(1) = False
        done(2) = False
        done(3) = False
        'MsgBox("item information count: " + tmpiteminfo2.Count.ToString)
        For f = 0 To tmpiteminfo2.Count - 1
            'MsgBox(tmpiteminfo2.Item(f).evaluationSource)
            Select Case tmpiteminfo2.Item(f).evaluationSource
                Case Is = "Gamestop"
                    tmpevalinfo.valuationsourceid = 1
                Case Is = "Amazon"
                    tmpevalinfo.valuationsourceid = 2
                Case Is = "Ebay"
                    tmpevalinfo.valuationsourceid = 3
                    'add more sources here later
            End Select
            Select Case tmpiteminfo2.Item(f).itemcondition
                Case Is = ItemCondition.Broken
                    'If done(0) = False Then
                    mode = pricefunctions.Mode(broken.ToArray)
                    max = pricefunctions.MaxValue(broken.ToArray)
                    min = pricefunctions.MinValue(broken.ToArray)
                    avg = pricefunctions.AveragePrice(broken.ToArray)
                    standarddev = pricefunctions.standarddeviation(broken.ToArray)
                    done(0) = True
                   ' End If
                Case Is = ItemCondition.LooksLikeNew
                    'If done(1) = False Then
                    mode = pricefunctions.Mode(Lookslikenew.ToArray)
                    max = pricefunctions.MaxValue(Lookslikenew.ToArray)
                    min = pricefunctions.MinValue(Lookslikenew.ToArray)
                    avg = pricefunctions.AveragePrice(Lookslikenew.ToArray)
                    standarddev = pricefunctions.standarddeviation(Lookslikenew.ToArray)
                    done(1) = True
                   ' End If
                Case Is = ItemCondition.SomeDamage
                    ' If done(2) = False Then
                    mode = pricefunctions.Mode(damaged.ToArray)
                    max = pricefunctions.MaxValue(damaged.ToArray)
                    min = pricefunctions.MinValue(damaged.ToArray)
                    avg = pricefunctions.AveragePrice(damaged.ToArray)
                    standarddev = pricefunctions.standarddeviation(damaged.ToArray)
                    done(2) = True
                   ' End If
                Case Is = ItemCondition.SomewhatUsed
                    'If done(3) = False Then
                    mode = pricefunctions.Mode(somewhatused.ToArray)
                    max = pricefunctions.MaxValue(somewhatused.ToArray)
                    min = pricefunctions.MinValue(somewhatused.ToArray)
                    avg = pricefunctions.AveragePrice(somewhatused.ToArray)
                    standarddev = pricefunctions.standarddeviation(somewhatused.ToArray)
                    done(3) = True
                    ' End If

            End Select

            'assign values to minimum price, maximum price, and the other prices. 
            If min > 0 Then
                tmpevalinfo.MinimumPrice = min
            End If
            If mode > 0 Then
                tmpevalinfo.ReoccuringPrice = mode
            End If
            If avg > 0 Then
                tmpevalinfo.avgprice = avg
            End If
            If max > 0 Then
                tmpevalinfo.MaximumPrice = max
            End If
            If standarddev > 0 Then  'And standarddev < 1 Then
                tmpevalinfo.avgdeviation = standarddev
            End If
            min = 0
            max = 0
            mode = 0
            avg = 0
            tmpevalinfo.currentItem = tmpiteminfo2.Item(f).name
            tmpevalinfo.evaluationcondition = tmpiteminfo2.Item(f).itemcondition
            'MsgBox(tmpiteminfo2.Item(f).itemcondition)
            tmpevalinfo.evaluated = True
            itemevalresultarr.Add(tmpevalinfo)

        Next f
        'Dim iteminfoc As New ItemInformation
        'For s = 0 To tmpiteminfo.Count - 1
        '    iteminfoc.itemsevaluate.Add(tmpiteminfo.Item(s).name)
        '    'add other item information and change to iteminfo type once I get information to display correctly on findquote form
        'Next s
        Dim itemval As New ItemValuation
        Dim tmpevalsource As New EvaluationSource
        Using uie As New DataAccess.SQLiteDb
            For h = 0 To tmpiteminfo.Count - 1
                tmpevalsource.EvaluationSourceName = tmpiteminfo.Item(h).evaluationSource
                tmpevalsource.EvaluationWebAddress = (From EvalWeb In uie.ValuationSources Where EvalWeb.ValuationSourceName = tmpevalsource.EvaluationSourceName Select EvalWeb).ToString
                Await itemval.archiveitem(tmpiteminfo.Item(h).name, tmpiteminfo.Item(h).name, tmpevalsource)
            Next
        End Using
        'delete all the evaluated items from the database for next evaluation

        Await ClearEvalTable()
        'return regular results
        Return itemevalresultarr
    Else
        'return automated evaluation results
        'results are archived as they are retrieved so delete data from the table below
        'delete all the evaluated items from the database for next evaluation
        Return autoitem
    End If

End Function

这是内部函数的签名:

Private Async Function GrabFromOnlineSource(itemname As String, WebsiteSource As String, progress As IProgress(Of Integer)) As Task(Of List(Of EvaluationInfo))

这是我迄今为止尝试过的方法(已更新):

第一次尝试:

  tmpevalitem = Await GrabFromOnlineSource(item.Item(i).name, item.Item(i).evaluationSource, New Progress(Of Integer)(Function(value) InlineAssignHelper(totalprogress, value))). 'replace totalprogress with the a integer I mentioned in the comments.
                  tmpevalitem.Wait()

第二次尝试:

   tmpevalitem = GrabFromOnlineSource(item.Item(i).name, item.Item(i).evaluationSource, New Progress(Of IProgress(Of Integer))(Function(value) InlineAssignHelper(evalprogress, value)))
                        tmpevalitem.Wait()

上面的代码虽然以关于数据类型进度不正确的错误告终。我确实需要将我的进度从 GrabFromOnlineSource 传递到 evalprogress 变量,否则我将向主程序发送不同的值。

注意:从技术上讲,我可以为每个使用的评估源调用 GrabFromOnlineSource(目前总共可能有 4 个)。此外,发送到 GrabFromOnlineSource 的每个评估源都有自己的进度报告,计入当前评估源(即 ebay 有自己的进度,amazon 有自己的进度,等等)。

EvaluationInfo 和 ItemInfo 结构:

     Public Structure EvaluationInfo
        Dim ReoccuringPrice As Double
        Dim MinimumPrice As Double
        Dim MaximumPrice As Double
        Dim avgprice As Double
        Dim avgdeviation As Double
        Dim currentItem As String
        Dim valuationsourceid As Integer
        Dim evaluationcondition As ItemCondition 'i.e. used,new,broken enum
        Dim evaluated As Boolean
    End Structure



 Public Structure ItemInfo
            Public Property name As String
            Public Property price As Double
            Public Property damaged As String
            Public Property aquisitiondate As Date
            Public Property evaluationSource As String
            Public Property itemcondition As ItemCondition
            Public Property itempicture As Byte()
            Public Property itemid As Integer

        End Structure

更多信息:

有一件事我忘了提到进度报告确实与 evaluateitem 函数中的 task.run 一起工作,但我更喜欢将我的代码模块化一点以防止一个动作花费太多 space 这就是为什么我尚未将代码从 GrabFromOnlineSource 移至 evaluateitem。

您是否尝试过在函数 GrabFromOnlineSource 中将一个变量声明为 byref 并传递给此方法。在 GrabFromOnlineSource 中使用模式后,您可以从主函数或任何其他地方观察此变量。

抱歉,我应该检查一下

方法 2

那么为什么你不把这个过程包装在 class 中,如果你想在 2 任务中取得进展,你可以随时观察这个对象或添加事件以进行进度跟踪

    Public Sub SomeMethod()
    Dim Wrap1 As New WrapConteiner
    Dim Wrap2 As New WrapConteiner
    Wrap2.Sleep = 200
    Dim Tasks(0 To 1) As Task
    Tasks(0) = New Task(AddressOf Wrap1.AwaitedProcessAsync)
    Tasks(1) = New Task(AddressOf Wrap2.AwaitedProcessAsync)
    Tasks(0).Start()
    Tasks(1).Start()
    Do While (Tasks(0).Status = TaskStatus.Running Or Tasks(1).Status = TaskStatus.Running Or Tasks(0).Status = TaskStatus.WaitingToRun Or Tasks(1).Status = TaskStatus.WaitingToRun)
        Task.WaitAll(Tasks, 10)
        Debug.Print("Wrap1: " & Wrap1.Progress)
        Debug.Print("Wrap2: " & Wrap2.Progress)
    Loop
    Debug.Print("B")
End Sub

Public Class WrapConteiner
    Property Progress As Integer
    Property Sleep As Integer = 100
    Public Sub AwaitedProcessAsync()
        Dim x As Integer
        For x = 1 To 100
            Me.Progress = x
            Threading.Thread.Sleep(Sleep)
        Next
    End Sub
End Class

很抱歉延迟回答我自己的问题,但这里是(我在格式化代码方面并不完美,所以编辑或管理员可以美化它):

这是 class 我在项目 dll 之外单独使用的测试代码来测试它是否有效(也就是我创建了一个新项目来测试我的理论):

Imports Windows.ApplicationModel.Core
Imports Windows.UI.Core

Public Class Progresstestclass
    Private Shared Property totalprogress As Integer
    Public Shared Async Function MainFunction(progress As IProgress(Of Integer)) As Task(Of Boolean)

        totalprogress = 5
        progress.Report(totalprogress)
        Dim a As New String("")
        Do While totalprogress > 0 And totalprogress < 70 And a <> "Success"
            Await InnerFunction(New Progress(Of Integer)(Function(value) InlineAssignHelper(totalprogress, value)))
            progress.Report(totalprogress - 5)
            Await System.Threading.Tasks.Task.Delay(1000)
            progress.Report(totalprogress)

        Loop
        Return True
    End Function
    Private Shared Async Function InnerFunction(progress2 As IProgress(Of Integer)) As Task(Of String)
    progress2.report(30)
            Await System.Threading.Tasks.Task.Delay(1000)
            progress2.Report(40)
          Await System.Threading.Tasks.Task.Delay(1000) 

        Return "Success"
    End Function
    Public Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
        target = value
        Return value
    End Function

End Class

另一个在我的 main 函数中发生变化的是我的 while 循环有点错误。我需要在传回进度报告之间进行延迟,否则它不会传回或最后以 100% 显示它,使我的进度报告无用。任何人仍然可以就如何做到这一点发表评论。忘记延迟会搞砸程序,这是一件疯狂的事情!

其他的都差不多。除了我像上面那样延迟让它停止传递进度足够长的时间让自然的眼睛看到正在发生的进展。