进度指示器控件是用户界面中非常常见的一个组件,它通常用于展示大量数据加载过程中的进度。本文将详细介绍如何设计和实现一个进度指示器控件,包括其背景、使用方法、代码实现和一些重要的注意事项。
设计一个进度指示器的关键在于创建活跃和非活跃的图像,并适当地放置它们以产生动画效果。在后台运行的计时器会持续更新活跃图像的位置,以保持动画的连贯性。控件设计为可定制的,可以在设计时进行调整,并在运行时以模态对话框的形式显示。这些图像通常为矩形,并且通过调用Bitmap.MakeTransparent
方法忽略背景。
进度指示器中图像的总数由DotsCount
属性控制。后台运行的计时器决定哪个索引被绘制为活跃状态,其余索引则绘制为非活跃状态。在绘制事件中,根据控件和图像的宽度计算出每个图像的位置,并绘制活跃和非活跃的图像。
void _progressTimer_Tick(object sender, EventArgs e)
{
this.ActiveIndex++;
if (ActiveIndex == this.DotsCount)
this.ActiveIndex = 0;
this.Refresh();
}
在绘制过程中,如果迭代器等于当前活跃索引,则绘制活跃图像;否则绘制非活跃图像。
while (iterator < this.DotsCount)
{
if (iterator == this.ActiveIndex)
{
e.Graphics.DrawImageUnscaled(this.ActiveImage, new Point(X, Y));
}
else
{
e.Graphics.DrawImageUnscaled(this.InActiveImage, new Point(X, Y));
}
}
默认的活跃和非活跃图像作为嵌入资源添加到程序集中,并在控件实例化时填充到属性中。
Stream imgStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Creatives.Resources.ActiveImage.png");
this._activeDot = Image.FromStream(imgStream);
(this._activeDot as Bitmap).MakeTransparent(Color.White);
imgStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Creatives.Resources.InActiveImage.png");
this._inactiveDot = Image.FromStream(imgStream);
(this._inactiveDot as Bitmap).MakeTransparent(Color.White);
当调用Show
方法时,控件被添加到WrapperForm
中,并填充到其大小,然后作为对话框窗口显示。
public void ShowProgressIndicator()
{
this.WrapperForm.Controls.Add(this);
this.WrapperForm.Size = this.Size;
this.Dock = DockStyle.Fill;
this.WrapperForm.ShowDialog();
}
为了避免内存泄漏,必须解除所有挂钩的事件,并且必须释放所有使用的非托管资源。
protected override void Dispose(bool disposing)
{
if (disposing)
{
_progressTimer.Tick -= new EventHandler(_progressTimer_Tick);
if (_wrapperForm != null)
{
_wrapperForm.Shown -= new EventHandler(wrapperFormShown);
}
}
base.Dispose(disposing);
}
包装表单不会接收鼠标激活,并且会保持在所有其他窗口的顶部;这是通过窗口样式的帮助实现的。
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x00000008 | 0x08000000;