您的位置:首页 > 其它

对进度条的通用封装实现

2013-12-29 23:00 274 查看

对进度条的通用封装实现

一直想写点啥对最近的工作做个总结,由于项目比较忙,可能还有自己的各种理由推脱有点懈怠,零碎的总结过一些,都没有动笔写下来过。眼看2013都要过去了,该写点啥来总结下。先从自己对进度封装的一点学习经验写出来,供大家交流,欢迎园子里的朋友不吝啬的拍砖。

首先定义对进度表示的契约,定义进度行为(IProgressor)、进度信息(IStepProgress)和中断处理(ITrackCancel)的接口如下:

/// <summary>
/// 进度行为接口
/// </summary>
public interface IProgressor
{
string Message { get; set; }
void Show();
void Hide();
void Step();
}


/// <summary>
/// 进度展示接口
/// </summary>
public interface IStepProgress : IProgressor
{
int MaxRange { get; set; }
int MinRange { get; set; }
int StepValue { get; set; }
i


/// <summary>
/// 中断接口
/// </summary>
public interface ITrackCancel
{
void Cancel();
bool Continue();
bool CancelOnClick { get; set; }
bool CancelOnKeyPress { get; set; }

IProgressor Progressor { get; set; }
}


实现进度信息接口,实现类(ProgressBarDialog)如下:

/// <summary>
/// 进度实现类
/// </summary>
public class ProgressBarDialog:IStepProgress
{

private int maxRange;
private int minRange;
private int stepValue;
private int position;
private string message;
private Task task;
private ProgressBarForm progressBarForm;
private CancellationTokenSource cancellationTokenSource;
private ITrackCancel trackCancel;

public Form ParentForm { get; set; }

public ITrackCancel TrackCancel
{
get { return trackCancel; }
set
{
if (value != null)
{
trackCancel = value;
trackCancel.Progressor = this;
}
if(progressBarForm != null)
progressBarForm.TrackCancel = value;

}
}

public int MaxRange
{
get { return maxRange; }
set
{
if (maxRange != value)
{
if (progressBarForm != null)
progressBarForm.MaxRange = value;
maxRange = value;
}
}
}

public int MinRange
{
get { return minRange; }
set
{
if (minRange != value)
{
if(progressBarForm != null)
progressBarForm.MinRange = value;
minRange = value;
}
}
}

public int StepValue
{
get { return stepValue; }
set
{
if (stepValue != value)
{
if (progressBarForm != null)
progressBarForm.StepValue = value;
stepValue = value;
}
}
}

public int Position
{
get { return position; }
set
{
if (progressBarForm != null)
progressBarForm.Position = value;
position = value;
}
}

public string Message
{
get { return message; }
set
{
if (message != value)
{
if (progressBarForm != null)
progressBarForm.Message = value;
message = value;
}
}
}

private void InitDialog()
{
if (progressBarForm == null)
progressBarForm = new ProgressBarForm(ParentForm);
progressBarForm.TopMost = true;
progressBarForm.MaxRange = this.MaxRange;
progressBarForm.MinRange = this.MinRange;
progressBarForm.StepValue = this.StepValue;
progressBarForm.Position = this.Position;
if (trackCancel != null)
progressBarForm.TrackCancel = this.TrackCancel;
if (!cancellationTokenSource.IsCancellationRequested)//此处的取消方法不是强制取消,CLR线程管理会在响应后合适的时候取消
{                                                     //这种线程取消的方式,一个目的是为了解决.NET4.0以前线程强制关闭的异常问题
if (progressBarForm.ShowDialog() == DialogResult.OK)
{

}
}
}

public void Show()
{
ShowDialog();
}

public void ShowDialog()
{
try
{
cancellationTokenSource = new CancellationTokenSource();
task = new Task(InitDialog, cancellationTokenSource.Token);
task.Start();
//此处创建的延续任务,为确保线程取消的时候,出现异常情况(如:进度UI还没有展示,主方法就已经走完)的保险处理
Task cancelTask = task.ContinueWith(
(cancellatinTask) =>
{
if (progressBarForm != null && progressBarForm.Visible)
progressBarForm.Hide();
}, TaskContinuationOptions.OnlyOnCanceled);
}
catch (Exception)
{
throw;
}
}

public void HideDialog()
{
try
{
if (progressBarForm == null)//当进度窗体还没有显示出来,进度线程监视的方法已经走完,取消task线程
cancellationTokenSource.Cancel();
else
{
MethodInvoker invoker = () =>
{
if (progressBarForm.Visible)
progressBarForm.Hide();
};
if (progressBarForm.InvokeRequired)
{
progressBarForm.Invoke(invoker);
}
else
{
invoker();
}
}
}
catch (Exception)
{
throw;
}
}

public void Hide()
{
HideDialog();
}

public void Step()
{
if (progressBarForm != null)
progressBarForm.Step();
}
}


实现进度展示的UI类(ProgressBarForm)如下:

public partial class ProgressBarForm : Form
{
public ProgressBarForm(Form parent)
{
InitializeComponent();
InitLocation(parent);
}

private void InitLocation(Form parent)
{
if (parent != null)
{
Left = parent.Left + (parent.Width - Width) / 2;
Top = parent.Top + (parent.Height - Height) / 2;
}
}

private int maxRange;
private int minRange;
private int stepValue;
private int position;
private string message;

public ITrackCancel TrackCancel { get; set; }

public string Message
{
get { return message; }
set
{
if (message != value)
{
MethodInvoker invoker = () => lab_Message.Text = value; ;
if (lab_Message.InvokeRequired)
{
//lab_Message.Invoke(invoker);
IAsyncResult asyncResult =lab_Message.BeginInvoke(invoker);
lab_Message.EndInvoke(asyncResult);
}
else
{
invoker();
}
message = value;
}
}
}

public int MaxRange
{
get { return maxRange; }
set
{
if (maxRange != value)
{
progressBar1.Maximum = value;
maxRange = value;
}
}
}

public int MinRange
{
get { return minRange; }
set
{
if (minRange != value)
{
progressBar1.Minimum = value;
minRange = value;
}
}
}

public int StepValue
{
get { return stepValue; }
set
{
if (stepValue != value)
{
progressBar1.Step = value;
stepValue = value;
}
}
}

public int Position
{
get { return position; }
set
{
if (position != value)
{
progressBar1.Value = value;
position = value;
}
}
}

public void Step()
{
MethodInvoker invoker = () =>
{
int newValue = progressBar1.Value + this.StepValue;
//当进度超过最大值,默认赋最小值
if (newValue > this.MaxRange)
{
progressBar1.Value = MinRange;
progressBar1.Refresh();
}
else
{
progressBar1.Value = newValue;
progressBar1.Refresh();
}
};
if (progressBar1.InvokeRequired)
{
//progressBar1.Invoke(invoker);
//采用异步委托的方法,提高进度条的响应速度,不知道线程创建多会不会影响效率(PS:没有研究过异步委托创建线程的方式,不知道是从线程池那线程,还是每次来就创建一个)
IAsyncResult asyncResult =progressBar1.BeginInvoke(invoker);
progressBar1.EndInvoke(asyncResult);
}
else
{
invoker();
}
}

private void ProgressBarForm_KeyDown(object sender, KeyEventArgs e)
{
if( e.KeyCode == Keys.Escape && TrackCancel.CancelOnKeyPress)
TrackCancel.Cancel();
}

private void btn_Cancel_Click(object sender, EventArgs e)
{
if (TrackCancel.CancelOnClick)
{
TrackCancel.Cancel();
}
}

protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
//当中断处理不支持按钮取消时候,将取消按钮不显示
if (!TrackCancel.CancelOnClick)
{
this.Height = 65;
}
}
}


下面完成对进度的调用进度条的简单封装类(DialogManager)如下:

/// <summary>
/// 管理进度条的方法类
/// </summary>
public class ProgressManager
{
public static IStepProgress ShowProgressBarDialog(ITrackCancel trackCancel,Form pForm)
{
if (trackCancel == null)
return null;
return new ProgressBarDialog() {TrackCancel = trackCancel,ParentForm = pForm};
}

public static IStepProgress ShowProgressBarDialog(ITrackCancel trackCancel, Form pForm,int maxRange,int minRange,int stepValue)
{
if (trackCancel == null)
return null;
return new ProgressBarDialog()
{
TrackCancel = trackCancel,
ParentForm = pForm,
MaxRange = maxRange,
MinRange = minRange,
StepValue = stepValue
};
}
}


最后,在自己代码中调用进度的写法如下:

private void button1_Click(object sender, EventArgs e)
{
ITrackCancel trackCancel = new CancelTracker() {CancelOnClick = true, CancelOnKeyPress = true};
IStepProgress stepProgress = ProgressManager.ShowProgressBarDialog(trackCancel,this);
stepProgress.MinRange = 0;
stepProgress.MaxRange = 100;
stepProgress.StepValue = 1;
bool pContinue = true;
stepProgress.Show();
for (int i = 0; i < 100; i++)
{
stepProgress.Message = String.Format("正在计算{0}...",i);
pContinue = trackCancel.Continue();
if(!pContinue)
break;
stepProgress.Step();
Thread.Sleep(50);
}
stepProgress.Hide();

}


以上为对简单进度条的封装过程,接口的定义参考了ArcGIS的接口定义方式。如果想增加对其它的进度条的支持,需要实现对应的进度条接口和对应的展示UI即可。如:想增加一个转圈等待的进度条展示进度,你只需要实现IProgressor接口,想支持中断处理,实例化实现ITrackCancel接口的类即可,可以用工厂模式来管理你的进度条展示。

题外的话:最近在学习fyiReporting和SharpDeveloper的源代码,fyiReporting的源代码太多,网上没发现什么知道的资源,看起来还是一知半解。SharpDeveloper的源码,网上资源大都讲的都是关于插件框架的东西,还有SharpDeveloper的团队也出过一本书的,讲的都是很久以前的版本。在此,求园友们对此感兴趣的能指导下学习fyiReporting或者SharpDeveloper的资料,或者一起共同学习。

本文的Demo:下载地址
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: