winform c# 自动更新,首先预览下截图
自动更新一般分3部分:
1、发现更新
2、下载文件
3、复制文件
http://www.cnblogs.com/liubiaocai/archive/2011/07/18/2109183.html
下面对以上3个过程做简单的介绍
发现更新
根据客户端的配置文件的manifestUri去读取服务器的xml文件,然后依次比较applicationId和version,如果applicationId一致且version不一致则可以更新,客户端配置文件不是app.config,而是一个自己定义的xml文件,至于为什么不用app.config文件的原因很简单,因为app.config在系统运行的时候是不能进行修改的,客户端配置文件内容大概如下:
<?
xml version="1.0" encoding="utf-8"
?>
< applicationUpdater applicationId ="{4a1e1623-bd3c-4921-8d91-85d34a5fe518}"
manifestUri ="http://127.0.0.1/manifests.xml"
version ="1.04" >
</ applicationUpdater >
< applicationUpdater applicationId ="{4a1e1623-bd3c-4921-8d91-85d34a5fe518}"
manifestUri ="http://127.0.0.1/manifests.xml"
version ="1.04" >
</ applicationUpdater >
applicationId表示运用程序Id,这个要跟服务器上的xml的applicationId一致,否则程序不会更新;
manifestUri表示服务器xml的地址
version表示当前版本,版本跟服务器上的不一致就更新
服务器端配置文件内容大概如下:
<?
xml version="1.0" encoding="utf-8"
?>
< manifest >
<!-- 版本号,无格式要求,更新时需要修改 -->
< version > 1.2 </ version >
< description > 更新说明,更新时需要修改 </ description >
<!-- applicationId运用程序ID,无格式要求,需要与客户端配置一样,否则不会进行更新 -->
< application applicationId ="{215E1AD7-9ABA-432f-A952-24BABA556850}" >
<!-- 重新启动exe名称,parameters启动时传入的参数 -->
< entryPoint file ="Client.exe" parameters ="client" />
<!-- 更新文件的目录,相对于更新系统,默认为同级目录 -->
< location > . </ location >
</ application >
<!-- base表示存放该文件的url -->
< files base ="http://localhost/update/" >
<!-- 文件名称,更新时需要修改 -->
< file source ="test.txt" />
< file source ="Client.exe" />
</ files >
</ manifest >
< manifest >
<!-- 版本号,无格式要求,更新时需要修改 -->
< version > 1.2 </ version >
< description > 更新说明,更新时需要修改 </ description >
<!-- applicationId运用程序ID,无格式要求,需要与客户端配置一样,否则不会进行更新 -->
< application applicationId ="{215E1AD7-9ABA-432f-A952-24BABA556850}" >
<!-- 重新启动exe名称,parameters启动时传入的参数 -->
< entryPoint file ="Client.exe" parameters ="client" />
<!-- 更新文件的目录,相对于更新系统,默认为同级目录 -->
< location > . </ location >
</ application >
<!-- base表示存放该文件的url -->
< files base ="http://localhost/update/" >
<!-- 文件名称,更新时需要修改 -->
< file source ="test.txt" />
< file source ="Client.exe" />
</ files >
</ manifest >
XML对应的实体类
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
[XmlRoot(
"
manifest
"
)]
public class Manifest
{
[XmlElement( " version " )]
public string Version { get ; set ; }
[XmlElement( " description " )]
public string Description { get ; set ; }
[XmlElement( " fileBytes " )]
public long FileBytes { get ; set ; }
[XmlElement( " application " )]
public Application Application { get ; set ; }
[XmlElement( " files " )]
public ManifestFiles ManifestFiles { get ; set ; }
}
public class ManifestFiles
{
[XmlElement( " file " )]
public ManifestFile[] Files { get ; set ; }
[XmlAttribute( " base " )]
public string BaseUrl { get ; set ; }
}
public class ManifestFile
{
[XmlAttribute( " source " )]
public string Source
{
get ;
set ;
}
[XmlAttribute( " hash " )]
public string Hash
{
get ;
set ;
}
}
public class Application
{
[XmlAttribute( " applicationId " )]
public string ApplicationId { get ; set ; }
[XmlElement( " location " )]
public string Location { get ; set ; }
[XmlElement( " entryPoint " )]
public EntryPoint EntryPoint { get ; set ; }
}
public class EntryPoint
{
[XmlAttribute( " file " )]
public string File { get ; set ; }
[XmlAttribute( " parameters " )]
public string Parameters { get ; set ; }
}
public class UpdaterConfigurationView
{
private static XmlDocument document = new XmlDocument();
private static readonly string xmlFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, " updateconfiguration.config " );
static UpdaterConfigurationView()
{
document.Load(xmlFileName);
}
public string Version
{
get
{
return document.SelectSingleNode( " applicationUpdater " ).Attributes[ " version " ].Value;
}
set
{
document.SelectSingleNode( " applicationUpdater " ).Attributes[ " version " ].Value = value;
document.Save(xmlFileName);
}
}
public string ApplicationId
{
get
{
return document.SelectSingleNode( " applicationUpdater " ).Attributes[ " applicationId " ].Value;
}
set
{
document.SelectSingleNode( " applicationUpdater " ).Attributes[ " applicationId " ].Value = value;
document.Save(xmlFileName);
}
}
public string ManifestUri
{
get
{
return document.SelectSingleNode( " applicationUpdater " ).Attributes[ " manifestUri " ].Value;
}
set
{
document.SelectSingleNode( " applicationUpdater " ).Attributes[ " manifestUri " ].Value = value;
document.Save(xmlFileName);
}
}
}
public class Manifest
{
[XmlElement( " version " )]
public string Version { get ; set ; }
[XmlElement( " description " )]
public string Description { get ; set ; }
[XmlElement( " fileBytes " )]
public long FileBytes { get ; set ; }
[XmlElement( " application " )]
public Application Application { get ; set ; }
[XmlElement( " files " )]
public ManifestFiles ManifestFiles { get ; set ; }
}
public class ManifestFiles
{
[XmlElement( " file " )]
public ManifestFile[] Files { get ; set ; }
[XmlAttribute( " base " )]
public string BaseUrl { get ; set ; }
}
public class ManifestFile
{
[XmlAttribute( " source " )]
public string Source
{
get ;
set ;
}
[XmlAttribute( " hash " )]
public string Hash
{
get ;
set ;
}
}
public class Application
{
[XmlAttribute( " applicationId " )]
public string ApplicationId { get ; set ; }
[XmlElement( " location " )]
public string Location { get ; set ; }
[XmlElement( " entryPoint " )]
public EntryPoint EntryPoint { get ; set ; }
}
public class EntryPoint
{
[XmlAttribute( " file " )]
public string File { get ; set ; }
[XmlAttribute( " parameters " )]
public string Parameters { get ; set ; }
}
public class UpdaterConfigurationView
{
private static XmlDocument document = new XmlDocument();
private static readonly string xmlFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, " updateconfiguration.config " );
static UpdaterConfigurationView()
{
document.Load(xmlFileName);
}
public string Version
{
get
{
return document.SelectSingleNode( " applicationUpdater " ).Attributes[ " version " ].Value;
}
set
{
document.SelectSingleNode( " applicationUpdater " ).Attributes[ " version " ].Value = value;
document.Save(xmlFileName);
}
}
public string ApplicationId
{
get
{
return document.SelectSingleNode( " applicationUpdater " ).Attributes[ " applicationId " ].Value;
}
set
{
document.SelectSingleNode( " applicationUpdater " ).Attributes[ " applicationId " ].Value = value;
document.Save(xmlFileName);
}
}
public string ManifestUri
{
get
{
return document.SelectSingleNode( " applicationUpdater " ).Attributes[ " manifestUri " ].Value;
}
set
{
document.SelectSingleNode( " applicationUpdater " ).Attributes[ " manifestUri " ].Value = value;
document.Save(xmlFileName);
}
}
}
下载文件
下载文件是根据服务器端的配置文件进行的,配置文件设置了下载的文件路径,下载地址的url,下载文件保存的位置,由location节点设置,好了,不多说了,看下载的源码,这里我是写了一个可以异步下载的组件,里面用的是Ms自带的WebClient类,异步下载有事件通知,详见源码:
事件类
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
public
class
DownloadErrorEventArgs : EventArgs
{
public Exception Error { get ; set ; }
public Manifest Manifest { get ; set ; }
}
public class DownloadProgressEventArgs : ProgressChangedEventArgs
{
public DownloadProgressEventArgs( int progressPercentage, object userState)
: base (progressPercentage,userState)
{ }
/// <summary>
/// 当前下载的文件名
/// </summary>
public string FileName { get ; set ; }
/// <summary>
/// 获取收到的字节数。
/// </summary>
public long BytesReceived { get ; set ; }
/// <summary>
/// 获取 System.Net.WebClient 数据下载操作中的字节总数。
/// </summary>
public long TotalBytesToReceive { get ; set ; }
}
public class DownloadCompleteEventArgs : AsyncCompletedEventArgs
{
public DownloadCompleteEventArgs(Exception error, bool cancelled, object userState)
: base (error, cancelled, userState)
{
}
public Manifest Manifest { get ; set ; }
}
{
public Exception Error { get ; set ; }
public Manifest Manifest { get ; set ; }
}
public class DownloadProgressEventArgs : ProgressChangedEventArgs
{
public DownloadProgressEventArgs( int progressPercentage, object userState)
: base (progressPercentage,userState)
{ }
/// <summary>
/// 当前下载的文件名
/// </summary>
public string FileName { get ; set ; }
/// <summary>
/// 获取收到的字节数。
/// </summary>
public long BytesReceived { get ; set ; }
/// <summary>
/// 获取 System.Net.WebClient 数据下载操作中的字节总数。
/// </summary>
public long TotalBytesToReceive { get ; set ; }
}
public class DownloadCompleteEventArgs : AsyncCompletedEventArgs
{
public DownloadCompleteEventArgs(Exception error, bool cancelled, object userState)
: base (error, cancelled, userState)
{
}
public Manifest Manifest { get ; set ; }
}
下载代码
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
public
class
DownloadClass : Component
{
private WebClient webClient = new WebClient();
private Manifest manifest;
private int fileCount = 0 ;
private bool cancel = false ;
private string tempPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, " temp " );
private HybridDictionary userStateToLifetime = new HybridDictionary();
private object defaultTaskId = new object ();
private delegate void WorkerEventHandler(AsyncOperation asyncOp);
private System.ComponentModel.Container components = null ;
private SendOrPostCallback onProgressReportDelegate;
private SendOrPostCallback onCompletedDelegate;
private AsyncOperation current;
/// <summary>
/// 下载进度
/// </summary>
public event EventHandler < DownloadProgressEventArgs > DownloadProgressChanged;
/// <summary>
/// 下载完成事件
/// </summary>
public event EventHandler < DownloadCompleteEventArgs > DownloadCompleted;
/// <summary>
/// 下载错误触发的事件
/// </summary>
public event EventHandler < DownloadErrorEventArgs > DownloadError;
public DownloadClass(IContainer container)
{
container.Add( this );
InitializeComponent();
InitializeDelegates();
}
public DownloadClass()
{
InitializeComponent();
InitializeDelegates();
}
/// <summary>
/// 初始化代理
/// </summary>
protected virtual void InitializeDelegates()
{
onProgressReportDelegate = new SendOrPostCallback(ReportProgress);
onCompletedDelegate = new SendOrPostCallback(DoDownloadCompleted);
}
/// <summary>
/// 触发下载进度事件
/// </summary>
/// <param name="e"></param>
protected virtual void OnDownloadProgressChanged(DownloadProgressEventArgs e)
{
if (DownloadProgressChanged != null )
{
DownloadProgressChanged( this , e);
}
}
/// <summary>
/// 触发下载完成事件
/// </summary>
/// <param name="e"></param>
protected virtual void OnDownloadCompleted(DownloadCompleteEventArgs e)
{
if (DownloadCompleted != null )
{
DownloadCompleted( this , e);
}
}
/// <summary>
/// 触发下载错误事件
/// </summary>
/// <param name="e"></param>
protected virtual void OnDownloadError(DownloadErrorEventArgs e)
{
if (DownloadError != null )
{
DownloadError( this , e);
}
}
/// <summary>
/// 下载文字保存的临时目录
/// </summary>
public string TempPath
{
get
{
return tempPath;
}
set
{
tempPath = value;
}
}
/// <summary>
/// 同步下载
/// </summary>
/// <param name="manifest"></param>
public void Download(Manifest manifest)
{
Init(manifest);
foreach (var file in manifest.ManifestFiles.Files)
{
string serverFileName = Path.Combine(manifest.ManifestFiles.BaseUrl, file.Source);
string clientFileName = Path.Combine(tempPath, file.Source);
Uri uri = new Uri(serverFileName);
if ( ! Directory.Exists(Path.GetDirectoryName(clientFileName)))
{
Directory.CreateDirectory(Path.GetDirectoryName(clientFileName));
}
webClient.DownloadFile(uri, clientFileName);
}
}
/// <summary>
/// 异步下载
/// </summary>
/// <param name="manifest"></param>
public void DownloadAsync(Manifest manifest)
{
Init(manifest);
DownloadAsync(manifest,defaultTaskId);
}
/// <summary>
/// 异步下载并指定任务Id
/// </summary>
/// <param name="manifest"></param>
/// <param name="taskId"></param>
public void DownloadAsync(Manifest manifest, object taskId)
{
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(taskId);
lock (userStateToLifetime.SyncRoot)
{
if (userStateToLifetime.Contains(taskId))
{
throw new ArgumentException( " 参数taskId必须是唯一的 " , " taskId " );
}
userStateToLifetime[taskId] = asyncOp;
}
WorkerEventHandler workerDelegate = new WorkerEventHandler(DownloadWorker);
workerDelegate.BeginInvoke(asyncOp, null , null );
}
private void Init(Manifest manifest)
{
this .manifest = manifest;
webClient.BaseAddress = manifest.ManifestFiles.BaseUrl;
webClient.Credentials = CredentialCache.DefaultCredentials;
webClient.Encoding = Encoding.UTF8;
}
/// <summary>
/// 异步下载方法
/// </summary>
/// <param name="asyncOp"></param>
private void DownloadWorker(AsyncOperation asyncOp)
{
current = asyncOp;
if ( ! TaskCanceled(asyncOp.UserSuppliedState))
{
try
{
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(webClient_DownloadFileCompleted);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
foreach (var file in manifest.ManifestFiles.Files)
{
string serverFileName = Path.Combine(manifest.ManifestFiles.BaseUrl, file.Source);
string clientFileName = Path.Combine(tempPath, file.Source);
Uri uri = new Uri(serverFileName);
if ( ! Directory.Exists(Path.GetDirectoryName(clientFileName)))
{
Directory.CreateDirectory(Path.GetDirectoryName(clientFileName));
}
while (webClient.IsBusy)
{
// 阻塞异步下载
}
if ( ! cancel)
{
webClient.DownloadFileAsync(uri, clientFileName, file.Source);
}
}
}
catch (Exception ex)
{
DownloadErrorEventArgs e = new DownloadErrorEventArgs();
e.Error = ex;
e.Manifest = manifest;
OnDownloadError(e);
}
}
}
/// <summary>
/// 异步完成方法
/// </summary>
/// <param name="exception"></param>
/// <param name="canceled"></param>
/// <param name="asyncOp"></param>
private void CompletionMethod(Exception exception, bool canceled, AsyncOperation asyncOp)
{
if ( ! canceled)
{
lock (userStateToLifetime.SyncRoot)
{
userStateToLifetime.Remove(asyncOp.UserSuppliedState);
}
}
DownloadCompleteEventArgs e = new DownloadCompleteEventArgs(exception, canceled, asyncOp.UserSuppliedState);
e.Manifest = manifest;
asyncOp.PostOperationCompleted(onCompletedDelegate, e);
current = null ;
}
/// <summary>
/// 异步下载进度事件(仅对于单个文件)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void webClient_DownloadProgressChanged( object sender, DownloadProgressChangedEventArgs e)
{
DownloadProgressEventArgs args = new DownloadProgressEventArgs(e.ProgressPercentage, e.UserState);
args.BytesReceived = e.BytesReceived;
args.FileName = e.UserState.ToString();
args.TotalBytesToReceive = e.TotalBytesToReceive;
if (current != null )
{
current.Post(onProgressReportDelegate, args);
}
}
/// <summary>
/// 异步下载完成事件(仅对于单个文件)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void webClient_DownloadFileCompleted( object sender, AsyncCompletedEventArgs e)
{
fileCount ++ ;
if (fileCount == manifest.ManifestFiles.Files.Length)
{
this .CompletionMethod(e.Error, TaskCanceled(current.UserSuppliedState), current);
}
}
/// <summary>
/// 取消异步下载
/// </summary>
public void CancelAsync()
{
CancelAsync(defaultTaskId);
}
/// <summary>
/// 取消异步下载
/// </summary>
public void CancelAsync( object taskId)
{
webClient.CancelAsync();
cancel = true ;
current = null ;
AsyncOperation asyncOp = userStateToLifetime[taskId] as AsyncOperation;
if (asyncOp != null )
{
lock (userStateToLifetime.SyncRoot)
{
userStateToLifetime.Remove(taskId);
}
}
}
private bool TaskCanceled( object taskId)
{
return cancel || (userStateToLifetime[taskId] == null );
}
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
protected override void Dispose( bool disposing)
{
if (disposing)
{
if (components != null )
{
components.Dispose();
}
}
base .Dispose(disposing);
}
private void DoDownloadCompleted( object operationState)
{
DownloadCompleteEventArgs e = operationState as DownloadCompleteEventArgs;
OnDownloadCompleted(e);
}
private void ReportProgress( object state)
{
DownloadProgressEventArgs e = state as DownloadProgressEventArgs;
OnDownloadProgressChanged(e);
}
}
{
private WebClient webClient = new WebClient();
private Manifest manifest;
private int fileCount = 0 ;
private bool cancel = false ;
private string tempPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, " temp " );
private HybridDictionary userStateToLifetime = new HybridDictionary();
private object defaultTaskId = new object ();
private delegate void WorkerEventHandler(AsyncOperation asyncOp);
private System.ComponentModel.Container components = null ;
private SendOrPostCallback onProgressReportDelegate;
private SendOrPostCallback onCompletedDelegate;
private AsyncOperation current;
/// <summary>
/// 下载进度
/// </summary>
public event EventHandler < DownloadProgressEventArgs > DownloadProgressChanged;
/// <summary>
/// 下载完成事件
/// </summary>
public event EventHandler < DownloadCompleteEventArgs > DownloadCompleted;
/// <summary>
/// 下载错误触发的事件
/// </summary>
public event EventHandler < DownloadErrorEventArgs > DownloadError;
public DownloadClass(IContainer container)
{
container.Add( this );
InitializeComponent();
InitializeDelegates();
}
public DownloadClass()
{
InitializeComponent();
InitializeDelegates();
}
/// <summary>
/// 初始化代理
/// </summary>
protected virtual void InitializeDelegates()
{
onProgressReportDelegate = new SendOrPostCallback(ReportProgress);
onCompletedDelegate = new SendOrPostCallback(DoDownloadCompleted);
}
/// <summary>
/// 触发下载进度事件
/// </summary>
/// <param name="e"></param>
protected virtual void OnDownloadProgressChanged(DownloadProgressEventArgs e)
{
if (DownloadProgressChanged != null )
{
DownloadProgressChanged( this , e);
}
}
/// <summary>
/// 触发下载完成事件
/// </summary>
/// <param name="e"></param>
protected virtual void OnDownloadCompleted(DownloadCompleteEventArgs e)
{
if (DownloadCompleted != null )
{
DownloadCompleted( this , e);
}
}
/// <summary>
/// 触发下载错误事件
/// </summary>
/// <param name="e"></param>
protected virtual void OnDownloadError(DownloadErrorEventArgs e)
{
if (DownloadError != null )
{
DownloadError( this , e);
}
}
/// <summary>
/// 下载文字保存的临时目录
/// </summary>
public string TempPath
{
get
{
return tempPath;
}
set
{
tempPath = value;
}
}
/// <summary>
/// 同步下载
/// </summary>
/// <param name="manifest"></param>
public void Download(Manifest manifest)
{
Init(manifest);
foreach (var file in manifest.ManifestFiles.Files)
{
string serverFileName = Path.Combine(manifest.ManifestFiles.BaseUrl, file.Source);
string clientFileName = Path.Combine(tempPath, file.Source);
Uri uri = new Uri(serverFileName);
if ( ! Directory.Exists(Path.GetDirectoryName(clientFileName)))
{
Directory.CreateDirectory(Path.GetDirectoryName(clientFileName));
}
webClient.DownloadFile(uri, clientFileName);
}
}
/// <summary>
/// 异步下载
/// </summary>
/// <param name="manifest"></param>
public void DownloadAsync(Manifest manifest)
{
Init(manifest);
DownloadAsync(manifest,defaultTaskId);
}
/// <summary>
/// 异步下载并指定任务Id
/// </summary>
/// <param name="manifest"></param>
/// <param name="taskId"></param>
public void DownloadAsync(Manifest manifest, object taskId)
{
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(taskId);
lock (userStateToLifetime.SyncRoot)
{
if (userStateToLifetime.Contains(taskId))
{
throw new ArgumentException( " 参数taskId必须是唯一的 " , " taskId " );
}
userStateToLifetime[taskId] = asyncOp;
}
WorkerEventHandler workerDelegate = new WorkerEventHandler(DownloadWorker);
workerDelegate.BeginInvoke(asyncOp, null , null );
}
private void Init(Manifest manifest)
{
this .manifest = manifest;
webClient.BaseAddress = manifest.ManifestFiles.BaseUrl;
webClient.Credentials = CredentialCache.DefaultCredentials;
webClient.Encoding = Encoding.UTF8;
}
/// <summary>
/// 异步下载方法
/// </summary>
/// <param name="asyncOp"></param>
private void DownloadWorker(AsyncOperation asyncOp)
{
current = asyncOp;
if ( ! TaskCanceled(asyncOp.UserSuppliedState))
{
try
{
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(webClient_DownloadFileCompleted);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
foreach (var file in manifest.ManifestFiles.Files)
{
string serverFileName = Path.Combine(manifest.ManifestFiles.BaseUrl, file.Source);
string clientFileName = Path.Combine(tempPath, file.Source);
Uri uri = new Uri(serverFileName);
if ( ! Directory.Exists(Path.GetDirectoryName(clientFileName)))
{
Directory.CreateDirectory(Path.GetDirectoryName(clientFileName));
}
while (webClient.IsBusy)
{
// 阻塞异步下载
}
if ( ! cancel)
{
webClient.DownloadFileAsync(uri, clientFileName, file.Source);
}
}
}
catch (Exception ex)
{
DownloadErrorEventArgs e = new DownloadErrorEventArgs();
e.Error = ex;
e.Manifest = manifest;
OnDownloadError(e);
}
}
}
/// <summary>
/// 异步完成方法
/// </summary>
/// <param name="exception"></param>
/// <param name="canceled"></param>
/// <param name="asyncOp"></param>
private void CompletionMethod(Exception exception, bool canceled, AsyncOperation asyncOp)
{
if ( ! canceled)
{
lock (userStateToLifetime.SyncRoot)
{
userStateToLifetime.Remove(asyncOp.UserSuppliedState);
}
}
DownloadCompleteEventArgs e = new DownloadCompleteEventArgs(exception, canceled, asyncOp.UserSuppliedState);
e.Manifest = manifest;
asyncOp.PostOperationCompleted(onCompletedDelegate, e);
current = null ;
}
/// <summary>
/// 异步下载进度事件(仅对于单个文件)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void webClient_DownloadProgressChanged( object sender, DownloadProgressChangedEventArgs e)
{
DownloadProgressEventArgs args = new DownloadProgressEventArgs(e.ProgressPercentage, e.UserState);
args.BytesReceived = e.BytesReceived;
args.FileName = e.UserState.ToString();
args.TotalBytesToReceive = e.TotalBytesToReceive;
if (current != null )
{
current.Post(onProgressReportDelegate, args);
}
}
/// <summary>
/// 异步下载完成事件(仅对于单个文件)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void webClient_DownloadFileCompleted( object sender, AsyncCompletedEventArgs e)
{
fileCount ++ ;
if (fileCount == manifest.ManifestFiles.Files.Length)
{
this .CompletionMethod(e.Error, TaskCanceled(current.UserSuppliedState), current);
}
}
/// <summary>
/// 取消异步下载
/// </summary>
public void CancelAsync()
{
CancelAsync(defaultTaskId);
}
/// <summary>
/// 取消异步下载
/// </summary>
public void CancelAsync( object taskId)
{
webClient.CancelAsync();
cancel = true ;
current = null ;
AsyncOperation asyncOp = userStateToLifetime[taskId] as AsyncOperation;
if (asyncOp != null )
{
lock (userStateToLifetime.SyncRoot)
{
userStateToLifetime.Remove(taskId);
}
}
}
private bool TaskCanceled( object taskId)
{
return cancel || (userStateToLifetime[taskId] == null );
}
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
protected override void Dispose( bool disposing)
{
if (disposing)
{
if (components != null )
{
components.Dispose();
}
}
base .Dispose(disposing);
}
private void DoDownloadCompleted( object operationState)
{
DownloadCompleteEventArgs e = operationState as DownloadCompleteEventArgs;
OnDownloadCompleted(e);
}
private void ReportProgress( object state)
{
DownloadProgressEventArgs e = state as DownloadProgressEventArgs;
OnDownloadProgressChanged(e);
}
}