在C/S项目中,通常会遇到一些耗时的操作,这个时候为了更好的客户体验,我们通常会加上一个进度条。 而且页面传值在C/S端也比较麻烦。毕竟不像B/S那样可以使用Session、QueryString、Cookie,或者提交表格等那么方便。
开始了:
页面很简单, 同样这里还有一个backgroundWorker类
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Threading;
namespace QuickLogisticsAssistant
{
public partial class BackgroundWorkerView : Form
{
public delegate void Action<in T1, in T2>(T1 arg1,T2 arg2);
public Action<BackgroundWorker, DoWorkEventArgs> DoWork { get; private set; }
public Action<BackgroundWorker, RunWorkerCompletedEventArgs> RunWorkerCompleted { get; private set; }
public RunWorkerCompletedEventArgs ExecutionResult { get; private set; }
public ApartmentState ThreadApartmentState { get; set; }
public BackgroundWorkerView(Action<BackgroundWorker, DoWorkEventArgs> doWork, Action<BackgroundWorker, RunWorkerCompletedEventArgs> runWorkerCompleted = null)
{
this.ThreadApartmentState = ApartmentState.MTA;
InitializeComponent();
this.Text = string.Format("{0} - 正在执行操作...", Application.ProductName);
this.DoWork = doWork;
this.RunWorkerCompleted = runWorkerCompleted;
this.progressBar1.Style = ProgressBarStyle.Marquee;
}
public BackgroundWorkerView(string title, Action<BackgroundWorker, DoWorkEventArgs> doWork, Action<BackgroundWorker, RunWorkerCompletedEventArgs> runWorkerCompleted = null)
{
this.ThreadApartmentState = ApartmentState.MTA;
InitializeComponent();
//this.Text = string.Format("正在{0}...", title);
this.Text = title;
this.DoWork = doWork;
this.RunWorkerCompleted = runWorkerCompleted;
this.progressBar1.Style = ProgressBarStyle.Marquee;
}
public BackgroundWorkerView(int upperBound, Action<BackgroundWorker, DoWorkEventArgs> doWork, Action<BackgroundWorker, RunWorkerCompletedEventArgs> runWorkerCompleted = null)
{
this.ThreadApartmentState = ApartmentState.MTA;
InitializeComponent();
this.Text = string.Format("{0} - 正在执行操作...", Application.ProductName);
this.DoWork = doWork;
this.RunWorkerCompleted = runWorkerCompleted;
this.progressBar1.Style = ProgressBarStyle.Continuous;
this.backgroundWorker1.WorkerReportsProgress = true;
this.progressBar1.Minimum = 0;
this.progressBar1.Maximum = upperBound;
}
public void RunWorkerAsync()
{
this.backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
if (this.ThreadApartmentState == ApartmentState.STA)
{
Exception error = null;
Thread th = new Thread(
delegate()
{
try
{
this.DoWork(sender as BackgroundWorker, e);
}
catch (Exception exception)
{
error = exception;
}
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
th.Join();
if (error != null)
throw error;
}
else
this.DoWork(sender as BackgroundWorker, e);
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (this.RunWorkerCompleted != null)
this.RunWorkerCompleted(sender as BackgroundWorker, e);
this.ExecutionResult = e;
//这一步是设置当前窗体为对话框,这样就可以将上面的Error传出去了
this.DialogResult = System.Windows.Forms.DialogResult.OK;
this.Close();
}
private void BackgroundWorkerView_FormClosing(object sender, FormClosingEventArgs e)
{
if (this.backgroundWorker1.IsBusy)
{
this.backgroundWorker1.CancelAsync();
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage == this.progressBar1.Maximum)
this.progressBar1.Style = ProgressBarStyle.Marquee;
else
this.progressBar1.Increment(e.ProgressPercentage);
}
private void BackgroundWorkerView_Load(object sender, EventArgs e)
{
this.RunWorkerAsync();
}
}
}
接下来看调用的方面:
_dicExcelInfo = new Dictionary<string, FileTableInfo>();
if (_selectFiles == null || _selectFiles.Count == 0)
{
MessageBox.Show("请选择文件!");
return;
}
//文件预处理,简单的判断是否完整
Application.DoEvents();
bool checkFail = false;
//这里调用该进度条窗体。此时,当里面的内容运行完,该窗体才关闭。
BackgroundWorkerView view = new BackgroundWorkerView("正在检查选择的文件是否完整...", (worker, arg) =>
{
foreach (var item in _selectFiles)
{
FileTableInfo zhi = ExcelHelper.CheckToExcel(item);
if (!_dicExcelInfo.ContainsKey(zhi.TradeDate))
{
_dicExcelInfo.Add(zhi.TradeDate, zhi);
}
else
{
if (zhi.XYFZBFlag)
{
//当前文件是信用负债文件
if (!_dicExcelInfo[zhi.TradeDate].XYFZBFlag)
{
//如果已经存在的当天的数据文件中,信用负债文件flag为负,则说明上一个文件不是信用负债文件
_dicExcelInfo[zhi.TradeDate].XYFZBFlag = zhi.XYFZBFlag;
_dicExcelInfo[zhi.TradeDate].XYFZBFile = zhi.XYFZBFile;
}
else
{
//导入了多个同一天的信用负债文件
MessageBox.Show(string.Format("选择了多个[{0}]的信用负债文件", zhi.TradeDate));
checkFail = true;
return;
}
}
if (zhi.JYBFlag)
{
//当前文件是交易数据文件
if (!_dicExcelInfo[zhi.TradeDate].JYBFlag)
{
_dicExcelInfo[zhi.TradeDate].JYBFlag = zhi.JYBFlag;
_dicExcelInfo[zhi.TradeDate].JYBFile = zhi.JYBFile;
}
else
{
//导入了多个同一天的交易文件
MessageBox.Show(string.Format("选择了多个[{0}]的交易数据文件", zhi.TradeDate));
//view.ExecutionResult = new RunWorkerCompletedEventArgs(false, new Exception(string.Format("选择了多个[{0}]的交易数据文件", zhi.TradeDate)), true);
checkFail = true;
return;
}
}
}
}
});
//设置进度条窗体为显示为对话框
var ret = view.ShowDialog();
if (ret == System.Windows.Forms.DialogResult.OK)
{
//如果错误不为空,则弹出错误信息
if (view.ExecutionResult.Error != null)
{
MessageBox.Show(view.ExecutionResult.Error.Message);
return;
}
}
if (ret == System.Windows.Forms.DialogResult.Cancel)
{
_dicExcelInfo = new Dictionary<string, FileTableInfo>();
return;
}
if (checkFail)
{
//检查失败
return;
}
string msg = "";
foreach (var tradeDate in _dicExcelInfo.Keys)
{
FileTableInfo exInfo = _dicExcelInfo[tradeDate];
if (exInfo.XYFZBFlag && exInfo.JYBFlag)
{
continue;
}
else if (!exInfo.XYFZBFlag)
{
msg += "日期为:" + tradeDate + " 缺失交易数据的文件 \r\n";
}
else if (!exInfo.JYBFlag)
{
msg += "日期为:" + tradeDate + " 缺失信用账户数据的文件 \r\n";
}
}
if (!string.IsNullOrEmpty(msg))
{
MessageBox.Show(msg);
return;
}
//这一步是设置当前窗体为对话框,这一步是跨页面传值的重要的异步
this.DialogResult = System.Windows.Forms.DialogResult.OK;
this.Close();
调用ImportData页面 的信息
ImportData imp = new ImportData();
if (imp.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
//选择了一批文件
Dictionary<string, FileTableInfo> dicSelectFiles = imp.DicExcelInfo;