很多情况下,我们在处理大数据时需要使用进度条,尤其是以模式窗口打开的进度条。
使用以模式窗口打开的进度条有两个好处。
第一,可以增加用户友好性。
第二,可以防止用户在等待时间多次点击页面按钮。
先说一下主要实现思想:
都知道如果在主窗体打开任何一个模式窗口时,当前窗体的进程将停止,知道模式窗口关闭为止,
这时如何才能突破这个一成不变的定律呢?
哈哈猜对了,就是它!使用线程~~~~
我们可以使用一个线程在主窗体上打开一个模式窗口,而且这个模式窗口还不会影响主窗体的线性执行逻辑!
下面就是代码实现了:
//1 建立一个有进度条(pbar 为进度条控件的名字)的Form窗体,并外公布几个进度条的必要属性
#region 属性
/// <summary>
/// 设置进度条的最小值(默认1)
/// </summary>
public int ProgersMinimum
{
set { pbar.Minimum = value; }
get { return pbar.Minimum; }
}
/// <summary>
/// 设置进度条的最最大值(默认100)
/// </summary>
public int ProgersMaximum
{
set { pbar.Maximum = value; }
get { return pbar.Maximum; }
}
/// <summary>
/// 设置进度条的当前值(默认1)
/// </summary>
public int ProgersValue
{
set { pbar.Value = value; }
get { return pbar.Value; }
}
/// <summary>
/// 设置进度条的步长大值(默认1)
/// </summary>
public int ProgersStep
{
set { pbar.Step = value; }
get { return pbar.Step; }
}
#endregion
#region 方法
/// <summary>
/// 增加进度
/// </summary>
/// <param name="value">需要增加的值</param>
/// <returns></returns>
public bool Increase(int value)
{
if (!this.IsHandleCreated)
return false;
//关闭进度条窗口
Action WinClose=(()=>{
this.Close();
});
//设置当前进度条位置
Action<int> SetProgresValue = ((val) => {
if (val < 0 || val > pbar.Maximum || val < pbar.Minimum)
{
pbar.Value = pbar.Maximum;
this.Close();
return;
}
pbar.Value = val;
});
try
{
this.Invoke(SetProgresValue, value);
}
catch
{
}
return !(value < 0 || value > pbar.Maximum || value < pbar.Minimum);
}
#endregion
//2.接下来就是在主窗体中的逻辑了
//2.1 声明 3 个类的成员变量
/// <summary>
/// 进度条窗体
/// </summary>
private CommonFrm.FrmProgres m_frmProgres = null;
/// <summary>
/// 控制进度条进度的代理
/// </summary>
/// <returns></returns>
private delegate bool DelIncreaseHandle(int value);
/// <summary>
/// 控制进度条进度的代理变量
/// </summary>
private DelIncreaseHandle m_ctrlProgresIncrease = null;
//2.2 编写一个打开进度条窗体的方法,如果要使用进度条时调一下就 OK 了
/// <summary>
/// 显示进度条
/// </summary>
/// <param name="maxiNum">进度条最大值</param>
/// <param name="miniNum">进度条最小值</param>
private void ShowProgress(int miniNum,int maxiNum)
{
Thread thread = null;
//1 打开进度条窗体
Action showDialogProgress = (() =>
{
m_frmProgres = new CommonFrm.FrmProgres();
m_frmProgres.FormClosed += delegate(object sender, FormClosedEventArgs e)
{
//添加这行代码会引发异常
//if (null != thread) //如果进度条界面关闭了,就终止打开窗体的进程
// thread.Abort();
};
m_ctrlProgresIncrease = new DelIncreaseHandle(m_frmProgres.Increase);
m_frmProgres.ProgersMinimum = miniNum; //设置进度条的最小值
m_frmProgres.ProgersMaximum = maxiNum;//设置进度条的最大值
m_frmProgres.StartPosition = FormStartPosition.CenterScreen; //进度条窗体打开的位置
m_frmProgres.ShowDialog(); //以模式状态打开进度条窗体
m_ctrlProgresIncrease = null;
m_frmProgres = null;
});
//2 启动线程
thread = new Thread(new ThreadStart(showDialogProgress));
thread.IsBackground = false; // 测试的时候这个东西似乎有点儿影响,没搞明白具体意思呢!
thread.Start();
/*
* 使线程睡眠一会儿,给窗口展现预留时间
* 窗体不展现前 m_ctrlProgresIncrease 为 null
* 将导致使用 this.Invoke 调用 m_ctrlProgresIncrease 委托时页面无限等待
*/
Thread.Sleep(1000);
}
// 接下来就是 调用了!!!!!!
/// <summary>
/// 测试
/// </summary>
private void btnTest_Click(object sender, EventArgs e)
{
int miniMun = 0;
int maxiNum = 100;
this.ShowProgress(miniMun, maxiNum); // 打开模式进度条窗口
for (int i = miniMun; i <= maxiNum; i++)
{
if(null != m_ctrlProgresIncrease)
this.BeginInvoke(m_ctrlProgresIncrease, i); // 设置进度条的值
Thread.Sleep(10);
}
if (null != m_ctrlProgresIncrease)
this.BeginInvoke(m_ctrlProgresIncrease, -1);
}
--------------------------------------
注意:上面用到了 this.BeginInvoke 和 this.Invoke
this.BeginInvoke :不需要等待调用的方法执行完毕
this.Invoke :需要等待调用的方法执行完毕
--------------------------------------
功能到此结束了!不过还不够灵活,如果在多个页面用还是要将 代码拷贝 过去。