Wpf 线程函数具有多个参数并返回数据

Wpf 线程函数具有多个参数并返回数据,wpf,multithreading,.net-3.5,dispatcher,Wpf,Multithreading,.net 3.5,Dispatcher,我正在开发一个WPF.NET3.5应用程序,它可以执行一些长任务,我想在UI线程中创建一个单独的线程来处理数据,然后在完成后更新UI中的一些标签。我遇到的问题是,我的函数使用了两个参数,我正在努力解决如何在线程中使用多个参数调用函数并更新UI 我一直在尝试使用委托子函数调用函数(它位于一个单独的类中),我的代码还试图从函数返回一个数据集,以便调用线程更新UI,但我不确定这是否是实现这一点的最佳实践,或者我是否应该使用调用函数的调度程序来进行UI更新(非常感谢反馈) 我的代码如下 Priv

我正在开发一个WPF.NET3.5应用程序,它可以执行一些长任务,我想在UI线程中创建一个单独的线程来处理数据,然后在完成后更新UI中的一些标签。我遇到的问题是,我的函数使用了两个参数,我正在努力解决如何在线程中使用多个参数调用函数并更新UI

我一直在尝试使用委托子函数调用函数(它位于一个单独的类中),我的代码还试图从函数返回一个数据集,以便调用线程更新UI,但我不确定这是否是实现这一点的最佳实践,或者我是否应该使用调用函数的调度程序来进行UI更新(非常感谢反馈)

我的代码如下

    Private Delegate Sub WorkHandler(ByVal input1 As String, ByVal input2 As String)
    Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
      Dim test_helper As New test_global
      Dim worker As New WorkHandler(AddressOf test_helper.getWeatherData)
      worker.BeginInvoke("IDA00005.dat", "Adelaide", AddressOf weatherCallBack, Nothing)

      ' The following is what I was using prior to attempting to work with threads, do I continue to update the UI here getting the called function to return a dataset, or do I have the called function do the UI updating?
      'Dim ls As DataSet = test_helper.getWeatherData("IDA00005.dat", "Adelaide")
      'Dim f_date As String = ls.Tables("weather").Rows(1).Item(3).ToString
    End Sub
    Public Sub weatherCallBack(ByVal ia As IAsyncResult)
        CType(CType(ia, Runtime.Remoting.Messaging.AsyncResult).AsyncDelegate, WorkHandler).EndInvoke(ia)
    End Sub
我尝试调用的函数如下所示:

Class test_global
  Public Sub getWeatherData(ByVal filename As String, ByVal location As String) 'As DataSet
    ...
  End Sub
End Class
Class Weather_test
  Implements INotifyPropertyChanged
  Private WithEvents worker As System.ComponentModel.BackgroundWorker
  Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
  Private Sub NotifyPropertyChanged(ByVal info As String)
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
  End Sub
  Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
    Dim test_helper As New test_global
    Dim worker = New System.ComponentModel.BackgroundWorker
    worker.WorkerReportsProgress = True
    worker.WorkerSupportsCancellation = True
    Dim str() = New String() {"IDA00005.dat", "Adelaide"}
    Try
      worker.RunWorkerAsync(str)
    Catch ex As Exception
      MsgBox(ex.Message)
    End Try
  End Sub
  Private Sub worker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles worker.DoWork
    Dim form_Helpder As New test_global
    Dim ds As DataSet = form_Helpder.getWeatherData(e.Argument(0), e.Argument(1))
    e.Result = ds
  End Sub
  Private Sub worker_Completed(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles worker.RunWorkerCompleted
    If e.Error IsNot Nothing Then
      MsgBox(e.Error.Message)
    Else
      ...
      NotifyPropertyChanged("lbl_minToday")
      ... 
    End If
  End Sub
End Class
我的问题是,如果要让调用线程更新UI,如何让被调用线程返回数据集,或者如果要让被调用线程更新UI,如何实现这一点

更新:

根据提供的建议,我实现了一个BackgroundWorker,它分别引发DoWork和RunWorkerCompleted事件来获取数据和更新UI。我的更新代码如下:

Class test_global
  Public Sub getWeatherData(ByVal filename As String, ByVal location As String) 'As DataSet
    ...
  End Sub
End Class
Class Weather_test
  Implements INotifyPropertyChanged
  Private WithEvents worker As System.ComponentModel.BackgroundWorker
  Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
  Private Sub NotifyPropertyChanged(ByVal info As String)
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
  End Sub
  Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
    Dim test_helper As New test_global
    Dim worker = New System.ComponentModel.BackgroundWorker
    worker.WorkerReportsProgress = True
    worker.WorkerSupportsCancellation = True
    Dim str() = New String() {"IDA00005.dat", "Adelaide"}
    Try
      worker.RunWorkerAsync(str)
    Catch ex As Exception
      MsgBox(ex.Message)
    End Try
  End Sub
  Private Sub worker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles worker.DoWork
    Dim form_Helpder As New test_global
    Dim ds As DataSet = form_Helpder.getWeatherData(e.Argument(0), e.Argument(1))
    e.Result = ds
  End Sub
  Private Sub worker_Completed(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles worker.RunWorkerCompleted
    If e.Error IsNot Nothing Then
      MsgBox(e.Error.Message)
    Else
      ...
      NotifyPropertyChanged("lbl_minToday")
      ... 
    End If
  End Sub
End Class
然后,我在一个单独的类中拥有获取和处理数据的函数

我能够在Visual Studio 2010中调试代码,表单显示,但标签没有更新,当我在RunWorkerAsync行中放置断点时,该行被调用,窗口加载子完成,但似乎没有调用DoWork或RunWorkerCompleted事件(至少函数没有)

有没有人可以提供一些帮助,让我调试代码,看看为什么没有调用这些函数

此外,上述代码是否是答案中建议的正确方法

我们将非常感谢您提供的任何帮助

Matt

您应该使用

您应该在
DoWork
处理程序中调用函数,并将
e.Result
设置为返回的数据集。
然后,您可以在
RunWorkerCompleted
处理程序中更新UI。

您应该使用

您应该在
DoWork
处理程序中调用函数,并将
e.Result
设置为返回的数据集。

然后,您可以在
RunWorkerCompleted
处理程序中更新UI。

我对
BackgroundWorker
没有太多经验(我只使用过一次),但它肯定是解决您问题的方法。然而,我经常使用的方法是启动一个新线程(不是通过委托的线程池线程),它获取一个锁,然后更新所有属性。如果类实现了INotifyPropertyChanged,则可以使用数据绑定使GUI在属性更改时自动更新。我用这种方法取得了很好的效果

至于向线程传递调度程序,我相信您也可以这样做。然而,我会轻描淡写,因为我相信我遇到过这样的情况:我认为我正在使用的调度程序不再与主线程关联。我有一个库,需要调用一个涉及GUI元素的方法(即使对话框可能不显示),我使用Dispatcher.Invoke解决了这个问题。我能够保证我使用的是与主线程关联的调度程序,因为我的应用程序使用MEF导出它


如果您想了解我发布的任何内容的更多详细信息,请发表评论,我会尽我所能对这些主题进行润色。

我对
BackgroundWorker
没有太多经验(我只使用过一次),但这绝对是解决您问题的方法。然而,我经常使用的方法是启动一个新线程(不是通过委托的线程池线程),它获取一个锁,然后更新所有属性。如果类实现了INotifyPropertyChanged,则可以使用数据绑定使GUI在属性更改时自动更新。我用这种方法取得了很好的效果

至于向线程传递调度程序,我相信您也可以这样做。然而,我会轻描淡写,因为我相信我遇到过这样的情况:我认为我正在使用的调度程序不再与主线程关联。我有一个库,需要调用一个涉及GUI元素的方法(即使对话框可能不显示),我使用Dispatcher.Invoke解决了这个问题。我能够保证我使用的是与主线程关联的调度程序,因为我的应用程序使用MEF导出它


如果您想了解我发布的任何内容的更多详细信息,请发表评论,我将尽我所能对这些主题进行润色。

请使用
BackgroundWorker
。实现长时间运行的方法,并将参数传递给
DoWork
事件处理程序的
DoWorkEventArgs
参数中的方法。在此方法中,不要直接或间接地更新UI(即不要更新视图模型的属性)

使用进度报告在方法运行时更新UI:在长时间运行的方法中调用
ReportProgress
,在
UserState
参数中传递需要显示在UI中的任何信息。在
ProgressChanged
事件处理程序中,从
progresschangedventargs
获取状态并更新UI(希望通过更新视图模型的适当属性并引发
PropertyChanged

您需要实现一个类来包含进度报告的用户状态,因为
UserState
属于
object
类型