开发windows窗体组件,由于业务复杂需要进度条,使用ProgressBar
控件。
winForm弹出窗口有两种方式:非模态窗口方式和模态窗口方式。
Show():非模态窗口方式(可以跟其他界面自由切换,而且不阻塞代码)
ShowDialog():模态窗口(必须关闭了该窗口,后面的代码才会执行,并且不能跟其他界面自由切换)。
这里面的进度条和我们开发web前端还不一样。我们知道js里,当我们弹出个进度框后,后面代码是可以执行的。在这里不行。
如果我们想用模态方式弹出框,同时还想执行后面代码。这种想法是实现不了了。只有一种办法(至少我这么认为)。将逻辑部份和组件放在一起,同时使用线程去更新UI。
这里以下载文件,同时显示进度条的功能为例。
新建一个windows窗体组件
,名字为DownLoadingForm
拖Label
和ProgressBar
组件到窗体里。如下
去掉头部的按钮(包括最大/最小/关闭按钮):将窗体的FormBorderStyle
设为None
。
代码如下:
using DongliCAD.utils;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace DongliCAD.component.common
{
public partial class DownLoadingForm : Form
{
private string downUrl;
private string savePath;
///
///
///
/// 下载url
/// 本地保存路径
public DownLoadingForm(string downUrl, string savePath)
{
this.downUrl = downUrl;
this.savePath = savePath;
InitializeComponent();
}
///
/// 启动线程
///
private void startThread()
{
//重新开一个线程用于更新UI
ThreadStart ts = new ThreadStart(startTime);
Thread thread = new Thread(ts);
thread.Name = "startTime";
thread.Start();
}
private System.Timers.Timer aTimer;
///
/// 定时器
///
private void startTime()
{
aTimer = new System.Timers.Timer();
aTimer.Elapsed += new System.Timers.ElapsedEventHandler(aTimer_Elapsed);
// 设置引发时间的时间间隔 此处设置为1秒
aTimer.Interval = 1000;
aTimer.Enabled = true;
//HttpDownUtil是我的下载类。
string resultPath = HttpDownUtil.HttpDownloadFile(downUrl, savePath);
if (!string.IsNullOrEmpty(resultPath))
{
CloseTime();
}
}
private delegate void SetProgressBarC(string str);
private void aTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
progressBar.Invoke(new EventHandler(delegate {
if (null != progressBar)
{
int currentValue = progressBar.Value;
currentValue += NumberUtil.getRandNum();
currentValue = currentValue >= 98 ? 98 : currentValue;
progressBar.Value = currentValue;
progressLbl.Text = "下载CAD文件进度:" + currentValue + "%";
if (progressBar.Value >= 100)
{
if(null != aTimer) {
aTimer.Enabled = false;
aTimer.Close();
}
}
}
}
));
}
public void CloseTime()
{
if (null != aTimer)
{
aTimer.Enabled = false;
aTimer.Close();
}
progressBar.Invoke(new EventHandler(delegate {
if (null != progressBar)
{
int currentValue = 100;
progressBar.Value = currentValue;
progressLbl.Text = "下载CAD文件进度:" + currentValue + "%";
Thread.Sleep(1000);
this.Close();
}
}
));
}
private void DownLoadingForm_Load(object sender, EventArgs e)
{
//组件初始化完成,启动线程
startThread();
}
}
}
其中注意下载方法HttpDownUtil.HttpDownloadFile
也必需放在新线程里执行。这里我只用了假的进度条,真实的太复杂
。
HttpDownUtil.cs
里HttpDownloadFile
方法:
///
/// 同步下载
/// Http下载文件
///
public static string HttpDownloadFile(string url, string path)
{
// 设置参数
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
if (GlobalData.Authorization.Length > 0)
{
request.Headers.Add("Authorization", GlobalData.Authorization);
}
//发送请求并获取相应回应数据
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
//直到request.GetResponse()程序才开始向目标网页发送Post请求
Stream responseStream = response.GetResponseStream();
//创建本地文件写入流
Stream stream = new FileStream(path, FileMode.Create);
byte[] bArr = new byte[1024];
int size = responseStream.Read(bArr, 0, (int)bArr.Length);
while (size > 0)
{
stream.Write(bArr, 0, size);
size = responseStream.Read(bArr, 0, (int)bArr.Length);
}
stream.Close();
responseStream.Close();
return path;
}
上面的下载是同步下载,如果在实时显示下载进度需要异常下载。下面代码是实时显示下载进度的代码。
///
/// 下载请求信息
///
public class DownloadTmp
{
///
/// 文件名
///
public string fileName;
///
/// 下载路径
///
public string filePath;
///
/// 下载进度回调
///
public Action loadingCallback;
///
/// 完成回调
///
public Action succeedCallback;
///
/// 失败回调
///
public Action failedCallback;
///
/// webRequest
///
public HttpWebRequest webRequest;
public long AllContentLength;
public long currentContentLength;
}
using DongliCAD.utils;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace DongliCAD.component.common
{
public partial class DownLoadingForm : Form
{
private string downUrl;
private string savePath;
private DownloadTmp downloadTmp;
///
///
///
/// 下载url
/// 本地保存路径
public DownLoadingForm(string downUrl, string savePath)
{
this.downUrl = downUrl;
this.savePath = savePath;
InitializeComponent();
}
///
/// 启动线程
///
private void startThread()
{
downloadTmp = new DownloadTmp();
downloadTmp.filePath = savePath;
HttpDownloadZip(downUrl, ref downloadTmp);
//HttpDownUtil.HttpDownloadFile("http://192.168.1.243:85/api/files/download/516610289672650758", savePath);
}
private void DownLoadingForm_Load(object sender, EventArgs e)
{
//组件初始化完成,启动线程
startThread();
}
private void updateProgressBar(long allContentLength, long currentContentLength)
{
Debug.Write("allContentLength: " + allContentLength + ",currentContentLength: " + currentContentLength);
progressBar.Invoke(new EventHandler(delegate {
if (null != progressBar)
{
int step = Convert.ToInt32(currentContentLength * 100 / allContentLength);
progressBar.Value = step;
progressLbl.Text = "下载CAD文件进度:" + step + "%";
}
}
));
}
///
/// 异步回调
///
/// Result.
private void BeginResponseCallback(IAsyncResult result)
{
DownloadTmp downloadInfo = (DownloadTmp)result.AsyncState;
HttpWebRequest Request = downloadInfo.webRequest;
HttpWebResponse Response = (HttpWebResponse)Request.EndGetResponse(result);
if (Response.StatusCode == HttpStatusCode.OK || Response.StatusCode == HttpStatusCode.Created)
{
string filePath = downloadInfo.filePath;
if (File.Exists(filePath))
{
File.Delete(filePath);
}
//FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write);
FileStream fs = File.OpenWrite(filePath);
Stream stream = Response.GetResponseStream();
int count = 0;
int num = 0;
long AllContentLength = Response.ContentLength;
long currentContentLength = 0;
if (Response.ContentLength > 0)
{
var buffer = new byte[2048 * 100];
do
{
num++;
count = stream.Read(buffer, 0, buffer.Length);
currentContentLength += count;
updateProgressBar(AllContentLength, currentContentLength);
fs.Write(buffer, 0, count);
if (downloadInfo.loadingCallback != null)
{
float pro = (float)fs.Length / Response.ContentLength * 100;
downloadInfo.loadingCallback((int)pro);
}
} while (count > 0);
}
fs.Close();
Response.Close();
if (downloadInfo.succeedCallback != null)
{
downloadInfo.succeedCallback();
}
progressBar.Invoke(new EventHandler(delegate {
this.Close();
this.DialogResult = DialogResult.OK;
}));
}
else
{
Response.Close();
if (downloadInfo.failedCallback != null)
{
downloadInfo.failedCallback();
}
progressBar.Invoke(new EventHandler(delegate {
this.Close();
this.DialogResult = DialogResult.Cancel;
}));
}
}
///
/// 下载文件,异步
///
/// 下载路径
/// 文件下载路径
///
public void HttpDownloadZip(string URL, ref DownloadTmp downloadInfo)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
if (GlobalData.Authorization.Length > 0)
{
request.Headers.Add("Authorization", GlobalData.Authorization);
}
downloadInfo.webRequest = request;
request.BeginGetResponse(BeginResponseCallback, downloadInfo);
}
}
}
---------------补充2019-01-22-----------------
使用BackgroundWorker做成一个上传进度条,外部传入进度值显示,对,就是和你心里想的一样的进度条。
private void BackgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
else if (e.Cancelled)
{
}
else
{
}
}
private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
startAssembly();
}
private void startAssembly()
{
//导出pdf
this.backgroundWorker1.ReportProgress(20, "正在导出PDF...(1/6)");
this.xExportPDF(this);
Boolean result = false;
this.backgroundWorker1.ReportProgress(30, "正在签出...(2/6)");
result = this.CheckOut();
this.backgroundWorker1.ReportProgress(40, "正在保存图纸...(3/6)");
result = this.DoSaveTitleWBaseInfo();
if (!result)
{
return;
}
this.SaveWorkspaceCadInfoVo();
this.backgroundWorker1.ReportProgress(60, "正在保存BOM...(4/6)");
result = this.SaveBom();
if (!result)
{
return;
}
this.backgroundWorker1.ReportProgress(80, "正在签入...(5/6)");
this.CheckIn();
closeTimeout();
this.backgroundWorker1.ReportProgress(100, "保存成功...(6/6)");
}
public partial class UploadLoadingWorkerForm : Form
{
private BackgroundWorker backgroundWorker;
///
///
///
public UploadLoadingWorkerForm(BackgroundWorker backgroundWorker)
{
InitializeComponent();
GlobalData.SetAutoScaleMode(this);
this.backgroundWorker = backgroundWorker;
this.backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
this.backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.DialogResult = DialogResult.OK;
this.Close();//执行完之后,直接关闭页面
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.progressBar.Value = e.ProgressPercentage;
this.progressLbl.Text = e.UserState.ToString();
}
最主要的是backgroundWorker1_ProgressChanged事件处理函数,外部通过 this.backgroundWorker1.ReportProgress(30, “正在签出…(2/6)”);传值,事件处理函数负责接收并显示进度和文本。
UploadLoadingWorkerForm uploadLoadingForm = new UploadLoadingWorkerForm ();
this.backgroundWorker1.RunWorkerAsync(); // 运行 backgroundWorker 组件
uploadLoadingForm = new UploadLoadingWorkerForm(this.backgroundWorker1);