近来需要写一个文件下载模块,用到多线程来显示进度条,后台线程进行文件下载,并通过委托更新主界面的进度条显示,但是发现会出现主界面卡主的情况,问题是否是由于进度条绘制(更新)是有主界面去绘制?我看到Application.DoEvents()并不会出现卡主界面的情况,有些迷惑,下面是我的代码,请各位帮忙看看啦:
public Form1()
{
InitializeComponent();
m_fileDownloader = new FileDownloader();
m_fileDownloader.FireOnShowProgress += new FileDownloader.ShowProgress(ShowProgress);
m_fileDownloader.FireOnSize += new FileDownloader.GetFileSize(fireOnFileSize);
} /// <summary>
/// 回调,用于处理进度条的最大值
/// </summary>
private void fireOnFileSize(long size)
{
if(InvokeRequired)
{
BeginInvoke(new FileDownloader.GetFileSize(fireOnFileSize), new Object[]{size});
return;
}
progressBar1.Maximum = (int)size;
progressBar1.Invalidate();
} /// <summary>
/// 回调,用于显示进度条
/// </summary>
private void ShowProgress(long npos)
{
if(InvokeRequired)
{
BeginInvoke(new FileDownloader.ShowProgress(ShowProgress), new Object[] {npos});
return;
} progressBar1.Value = (int)npos;
if(npos == progressBar1.Maximum)
{
progressBar1.Visible = false;
MessageBox.Show("下载完成");
}
} /// <summary>
/// 开始下载文件
/// </summary>
private void btnDownload_Click(object sender, EventArgs e)
{
m_fileDownloader.DownLoadFile("http://a.de-zhou.com/vip/lll/左边.mp3");
} public class FileDownloader
{
private string m_strUrl; public delegate void GetFileSize(long size);
public delegate void ShowProgress(long pos); /// <summary>
/// 用于处理文件的总长度
/// </summary>
public event GetFileSize FireOnSize;
/// <summary>
/// 用于处理文件的下载进度
/// </summary>
public event ShowProgress FireOnShowProgress; /// <summary>
/// 下载文件
/// </summary>
/// <param name="strUrl">下载地址</param>
public void DownLoadFile(string strUrl)
{
m_strUrl = strUrl;
Thread thread = new Thread(new ThreadStart(DownloadThread));
thread.Start();
} /// <summary>
/// 下载线程
/// </summary>
private void DownloadThread()
{
HttpWebRequest Myrq = (HttpWebRequest)HttpWebRequest.Create(m_strUrl);
HttpWebResponse Myrp = (HttpWebResponse)Myrq.GetResponse();
long totalBytes = Myrp.ContentLength;
if (FireOnSize != null)
FireOnSize(totalBytes); Stream st;
try
{
st = Myrp.GetResponseStream();
}
catch (System.Exception e)
{
return;
}
string strFileName = "";
int npos = m_strUrl.LastIndexOf("/");
if(npos != -1)
strFileName = m_strUrl.Substring(npos +1, m_strUrl.Length - npos -1);
string strPath = "\\Storage Card\\" + strFileName;
Stream so = new FileStream(strPath, FileMode.Create); long totalDownloadedByte = 0;
byte[] by = new byte[1024];
int osize = st.Read(by, 0, (int)by.Length);
while (osize > 0)
{
totalDownloadedByte = osize + totalDownloadedByte;
so.Write(by, 0, osize); if (FireOnShowProgress != null)
FireOnShowProgress(totalDownloadedByte); osize = st.Read(by, 0, (int)by.Length);
}
so.Close();
st.Close();
}
}
public Form1()
{
InitializeComponent();
m_fileDownloader = new FileDownloader();
m_fileDownloader.FireOnShowProgress += new FileDownloader.ShowProgress(ShowProgress);
m_fileDownloader.FireOnSize += new FileDownloader.GetFileSize(fireOnFileSize);
} /// <summary>
/// 回调,用于处理进度条的最大值
/// </summary>
private void fireOnFileSize(long size)
{
if(InvokeRequired)
{
BeginInvoke(new FileDownloader.GetFileSize(fireOnFileSize), new Object[]{size});
return;
}
progressBar1.Maximum = (int)size;
progressBar1.Invalidate();
} /// <summary>
/// 回调,用于显示进度条
/// </summary>
private void ShowProgress(long npos)
{
if(InvokeRequired)
{
BeginInvoke(new FileDownloader.ShowProgress(ShowProgress), new Object[] {npos});
return;
} progressBar1.Value = (int)npos;
if(npos == progressBar1.Maximum)
{
progressBar1.Visible = false;
MessageBox.Show("下载完成");
}
} /// <summary>
/// 开始下载文件
/// </summary>
private void btnDownload_Click(object sender, EventArgs e)
{
m_fileDownloader.DownLoadFile("http://a.de-zhou.com/vip/lll/左边.mp3");
} public class FileDownloader
{
private string m_strUrl; public delegate void GetFileSize(long size);
public delegate void ShowProgress(long pos); /// <summary>
/// 用于处理文件的总长度
/// </summary>
public event GetFileSize FireOnSize;
/// <summary>
/// 用于处理文件的下载进度
/// </summary>
public event ShowProgress FireOnShowProgress; /// <summary>
/// 下载文件
/// </summary>
/// <param name="strUrl">下载地址</param>
public void DownLoadFile(string strUrl)
{
m_strUrl = strUrl;
Thread thread = new Thread(new ThreadStart(DownloadThread));
thread.Start();
} /// <summary>
/// 下载线程
/// </summary>
private void DownloadThread()
{
HttpWebRequest Myrq = (HttpWebRequest)HttpWebRequest.Create(m_strUrl);
HttpWebResponse Myrp = (HttpWebResponse)Myrq.GetResponse();
long totalBytes = Myrp.ContentLength;
if (FireOnSize != null)
FireOnSize(totalBytes); Stream st;
try
{
st = Myrp.GetResponseStream();
}
catch (System.Exception e)
{
return;
}
string strFileName = "";
int npos = m_strUrl.LastIndexOf("/");
if(npos != -1)
strFileName = m_strUrl.Substring(npos +1, m_strUrl.Length - npos -1);
string strPath = "\\Storage Card\\" + strFileName;
Stream so = new FileStream(strPath, FileMode.Create); long totalDownloadedByte = 0;
byte[] by = new byte[1024];
int osize = st.Read(by, 0, (int)by.Length);
while (osize > 0)
{
totalDownloadedByte = osize + totalDownloadedByte;
so.Write(by, 0, osize); if (FireOnShowProgress != null)
FireOnShowProgress(totalDownloadedByte); osize = st.Read(by, 0, (int)by.Length);
}
so.Close();
st.Close();
}
}
{
if(InvokeRequired)
{
BeginInvoke(new FileDownloader.ShowProgress(ShowProgress), new Object[] {npos});
return;
}
Application.DoEvents();
progressBar1.Value = (int)npos;
if(npos == progressBar1.Maximum)
{
progressBar1.Visible = false;
MessageBox.Show("下载完成");
}
}
把更新界面的放到完成事件里,
backgroundworker天生就是做这个的
根据txg92的说法,那我上面那个事采用异步回调,照理也不会出现界面卡主的情况啊?是否连那个绘制进度条的任务也应该交给后台线程操作?不知道是否有更好的方法呢?