Threaded Function有多个参数并返回数据
我正在做一个WPF .NET 3.5应用程序,它执行几个长任务,我想使UI线程分离线程来处理数据,然后在完成更新时UI中的标签。我遇到的问题是我使用两个参数的功能,我正在努力解决如何在一个线程中调用带有多个参数的函数并更新UI。Threaded Function有多个参数并返回数据
我一直在玩弄使用Delegate Sub来调用函数(它位于一个单独的类),我的代码也试图从调用线程的函数返回一个数据集来更新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
我的问题是,如果我是有调用线程更新UI,我怎么有被调用线程要返回一个数据集,或者如果被调用的线程要更新UI,我该如何去做到这一点?
更新:
按照提供的recomendations,我impletemented这引起了DoWork的和RunWorkerCompleted事件来获取数据,并更新了UI,分别一个BackgroundWorker。我更新的代码如下:
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行放置一个断点时,该行被调用并且Window_Loaded子完成,但看起来没有的DoWork或RunWorkerCompleted事件被调用(至少该函数不是)。
任何人都可以提供一些帮助我如何调试代码,看看为什么这些函数不被调用?
另外,上述代码是在答案中推荐的正确方法吗?
提供的任何援助将不胜感激。
马特
使用BackgroundWorker
。实现您的长时间运行的方法,并将参数传递给DoWork
事件处理函数的参数DoWorkEventArgs
中的方法。不要在此方法中直接或间接更新UI(即不要更新视图模型的属性)。
使用进度报告在方法运行时更新用户界面:在长时间运行的方法中调用ReportProgress
,传递需要在UserState
参数中显示在用户界面中的任何信息。在ProgressChanged
事件处理程序中,从ProgressChangedEventArgs
获取状态并更新UI(希望通过更新视图模型的适当属性并提高PropertyChanged
)来更新UI。
由于UserState
的类型为object
,因此您需要实施一个类来包含进度报告的用户状态。
请注意,您也可以在完成时使用长时间运行方法的结果更新UI。这是以类似于进度报告的方式完成的:执行一个类来包含结果,将DoWorkEventArgs
的Result
属性设置为该类的一个实例,当RunWorkerCompleted
事件发生时,结果将在WorkCompletedEventArgs
的Result
属性中可用被提出。
确保您通过检查WorkCompletedEventArgs
的Error
属性来处理长时间运行的方法引发的任何异常。
您应该使用BackgroundWorker component。
您应该在DoWork
处理程序中调用您的函数,并将e.Result
设置为返回的DataSet。
然后,您可以更新RunWorkerCompleted
处理程序中的UI。
我对BackgroundWorker
没有太多经验(我只用过一次),但它绝对是解决您的问题的方法。然而,我总是使用的方法是启动一个新的线程(而不是通过委托的线程池线程),该线程获取一个锁并更新所有的属性。假如你的类实现了INotifyPropertyChanged
,那么你可以使用数据绑定来让GUI在任何时候属性改变时自动更新。采用这种方法,我获得了很好的结果。
只要将调度程序传递给你的线程,我相信你也可以做到这一点。不过,我会轻率地行事,因为我相信我遇到过这种情况,我认为我使用的调度程序不再与主线程相关联。我有一个库需要调用一个触及GUI元素的方法(即使对话框可能不显示),我使用Dispatcher.Invoke解决了这个问题。我能够保证我使用与主线程相关联的Dispatcher,因为我的应用程序使用MEF导出它。
如果您想了解更多关于我发布的任何内容的详细信息,请发表评论,我会尽我所能对这些主题进行修饰。
这将无法正常工作;您将从bckground线程更新UI对象。另外,你应该使用ThreadPool。 – SLaks 2011-01-12 17:17:09
当您使用“BackgroundWorker”的进度报告功能时,您可以更新UI对象。很少有必要在WPF应用程序中显式使用`System.Threading`。 – 2011-01-12 18:06:50
我已经更新了这个问题,我已经按照推荐实现了BackgroundWorker,但是我遇到了两个函数来处理DoWork和RunWorkerCompleted事件的问题。 – Lima 2011-01-13 11:47:35