.NET 3.0 WPF
Control.Invoke变成了Dispatcher.Invoke。内部实现还是一样的,有一个Callback队列,然后PostMessage。同时引入的还有DispatcherSynchronizationContext。
Conculsion
从直接PostMessage到Control.Invoke到SynchronizationContext到AsyncOperationManager到BackgroundWorker,职责最终推卸到了回调的提供方。但是由于引入的时间不一致,很多回调提供方是没有使用AsyncOperation的。这个时候,我们自己需要自己去包装,比如:
using System;
using System.ComponentModel;
using System.Net;
using log4net;
namespace xxx
{
public class WebClientFileUploader : FileUploaderListeners, FileUploader
{
private static readonly ILog LOGGER = LogManager.GetLogger(typeof (WebClientFileUploader));
private readonly WebClient webClient;
private readonly Uri address;
private readonly AsyncOperation asyncOperation;
public WebClientFileUploader(Uri address)
{
asyncOperation = AsyncOperationManager.CreateOperation(null);
webClient = new WebClient();
webClient.UploadFileCompleted += HandleUploadFileCompleted;
this.address = address;
}
private void HandleUploadFileCompleted(object sender, UploadFileCompletedEventArgs eventArgs)
{
try
{
var result = eventArgs.Result;
LOGGER.Info("Request completed.");
asyncOperation.Post(state => HandleCompleted(result), null);
}
catch (Exception exception)
{
LOGGER.Error("Request failed.", exception);
asyncOperation.Post(state => HandleError(exception), null);
}
}
public void Cancel()
{
LOGGER.Info("Cancelling the request.");
webClient.CancelAsync();
}
public void Upload(string fileName)
{
LOGGER.Info("Starting to upload to " + address + " with file " + fileName + " using real web client.");
webClient.UploadFileAsync(address, WebRequestMethods.Http.Post, fileName);
}
}
}
using System.ComponentModel;
using System.Net;
using log4net;
namespace xxx
{
public class WebClientFileUploader : FileUploaderListeners, FileUploader
{
private static readonly ILog LOGGER = LogManager.GetLogger(typeof (WebClientFileUploader));
private readonly WebClient webClient;
private readonly Uri address;
private readonly AsyncOperation asyncOperation;
public WebClientFileUploader(Uri address)
{
asyncOperation = AsyncOperationManager.CreateOperation(null);
webClient = new WebClient();
webClient.UploadFileCompleted += HandleUploadFileCompleted;
this.address = address;
}
private void HandleUploadFileCompleted(object sender, UploadFileCompletedEventArgs eventArgs)
{
try
{
var result = eventArgs.Result;
LOGGER.Info("Request completed.");
asyncOperation.Post(state => HandleCompleted(result), null);
}
catch (Exception exception)
{
LOGGER.Error("Request failed.", exception);
asyncOperation.Post(state => HandleError(exception), null);
}
}
public void Cancel()
{
LOGGER.Info("Cancelling the request.");
webClient.CancelAsync();
}
public void Upload(string fileName)
{
LOGGER.Info("Starting to upload to " + address + " with file " + fileName + " using real web client.");
webClient.UploadFileAsync(address, WebRequestMethods.Http.Post, fileName);
}
}
}
这样,我们就不需要在手工地去用Control.Invoke了,也不应该再直接用Control.Invoke了。