ProcessFile()
是否在UIThread或单独的线程上运行。如果它在UIThread上,如何将文件请求和ProcessFile()移动到单独的Thread
?
var xClient = new ServiceReference1.Service1SoapClient();
xClient.Retrieve_File_Completed += new EventHandler<ServiceReference1.Retrieve_File_CompletedCompletedEventArgs>(xClient_Retrieve_File_Completed);
.
.//called on Page load
foreach(fileName in fileNames)
{
xClient.Retrieve_FileAsync(fileName);
}
.
.
void xClient_Retrieve_File_Completed(object sender, ServiceReference1.Retrieve_File_CompletedCompletedEventArgs e)
{
//Processing
ProcessFile(e.Result[0]); //Is this on UI Thread?
}
编辑:从答案中可以清楚地看到ProcessFile()
在UI线程上运行。如何将文件请求和处理(ProcessFile()
)移动到单独的线程。 ProcessFile
只填充一些数据结构,在收到所有文件后使用哪些UI进行更改。
答案 0 :(得分:2)
使用“添加服务引用”功能时,Visual Studio自动生成的服务代理将自动在启动服务调用的线程上分派已完成的回调事件。
在您的情况下,这意味着您的UI线程确实执行了xClient_Retrieve_File_Completed
。
<强>更新强> 实际上很难将文件请求和文件处理全部放在一个线程上,然后在所有请求和处理完成后更新UI,因为在完成对服务的请求时必须保持线程处于活动状态。无法保证服务请求将按照发送顺序完成,因此您必须跟踪已完成请求的数量,并且只有在所有请求完成后,您才能通知UI并结束线程。
对我而言,这听起来像一个脆弱而复杂的设计,不幸的是,你可能用于此类设计的CountDownEvent
在Silverlight中不存在。
或者,您可以考虑更改服务和ProcessFile
的设计,以便您可以同时请求和处理所有文件,这样您只需要发出一个服务请求(除非您发送大量数据)通过网络往返服务)。然后,您可以生成BackgroundWorker
(as suggested by Matthew Paul Keelan in his answer)以一次性处理所有文件。您的代码看起来与此类似:
// Called on Page load.
// Note that there is only one service call with all file names as parameter.
xClient.Retrieve_FileAsync(fileNames);
// ...
// Elsewhere in the class
BackgroundWorker _worker;
void xClient_Retrieve_File_Completed(object sender, ServiceReference1.Retrieve_File_CompletedCompletedEventArgs e)
{
_worker = new BackgroundWorker()
_worker.DoWork += (sender, args) =>
{
// Only one call to ProcessFile.
ProcessFile(e.Result);
};
_worker.RunWorkerCompleted += (sender, args) =>
{
// Update UI here
};
_worker.RunWorkerAsync();
}
答案 1 :(得分:1)
您可以使用Dispatcher.CheckAccess()方法确定代码是否在UI线程上执行:
如果ProcessFile方法是一项昂贵的操作,您可以尝试将其卸载到BackgroundWorker。 Pete Brown在这里有一个很好的描述:
The UI Thread, Dispatchers, Background Workers and Async Network Programming