using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Threading; using System.Windows.Forms; using ThreadingTimer = System.Threading.Timer; using UITimer = System.Windows.Forms.Timer; namespace InvoicingTool { /// /// 表示一个加载圆圈动画 /// [ToolboxBitmap(typeof(LoadingCircle), "LoadingCircleIcon.png")] public partial class LoadingCircle : UserControl { #region 构造 public LoadingCircle() { InitializeComponent(); //双缓冲,禁擦背景 SetStyle( ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true); //初始化绘图timer _graphicsTmr = new UITimer { Interval = 1 }; //Invalidate()强制重绘,绘图操作在OnPaint中实现 _graphicsTmr.Tick += (sender1, e1) => Invalidate(false); _dotSize = Width / 10f; //初始化"点" DotCount = 5; _dots = new Dot[DotCount]; Color = Color.White; } #endregion 构造 #region 属性 /// /// 圆心 /// [Browsable(false)] public PointF CircleCenter { get { return new PointF(Width / 2f, Height / 2f); } } /// /// 半径 /// [Browsable(false)] public float CircleRadius { get { return Width / 2f - _dotSize; } } /// /// 颜色 /// [Browsable(true), Category("Appearance"), Description("设置\"点\"的前景色")] public Color Color { get; set; } /// /// 数量 /// [Browsable(true),Category("Appearance"),Description("设置\"点\"的数量\n有效值1-10"),DefaultValue(5)] public UInt32 DotCount { get; set; } #endregion 属性 #region 字段 //点数组 private Dot[] _dots; //Timers private readonly UITimer _graphicsTmr; private ThreadingTimer _actionTmr; //点大小 private float _dotSize; //是否活动 private bool _isActived; //是否绘制:用于状态重置时挂起与恢复绘图 private bool _isDrawing = true; //Timer计数:用于延迟启动每个点 private int _timerCount; #endregion 字段 #region 常量 //动作间隔(Timer) private const int ActionInterval = 30; //计数基数:用于计算每个点启动延迟:index * timerCountRadix private const int TimerCountRadix = 45; #endregion 常量 #region 方法 //检查是否重置 private bool CheckToReset() { return _dots.Count(d => d.Opacity > 0) == 0; } //初始化点元素 private void CreateDots() { if (DotCount < 1 || DotCount > 10) DotCount = 5; _dots = new Dot[DotCount]; for (int i = 0; i < _dots.Length; ++i) _dots[i] = new Dot(CircleCenter, CircleRadius); } /// /// 开关 /// public bool Switch() { if (!_isActived) Start(); else Stop(); return _isActived; } /// /// 开始 /// public void Start() { CreateDots(); _timerCount = 0; foreach (Dot dot in _dots) dot.Reset(); _graphicsTmr.Start(); //初始化动作timer _actionTmr = new ThreadingTimer( state => { //动画动作 for (int i = 0; i < _dots.Length; i++) if (_timerCount++ > i * TimerCountRadix) _dots[i].DotAction(); //是否重置 if (CheckToReset()) { //重置前暂停绘图 _isDrawing = false; _timerCount = 0; foreach (Dot dot in _dots) dot.Reset(); //恢复绘图 _isDrawing = true; } _actionTmr.Change(ActionInterval, Timeout.Infinite); }, null, ActionInterval, Timeout.Infinite); _isActived = true; } /// /// 停止 /// public void Stop() { _graphicsTmr.Stop(); _actionTmr.Dispose(); _isActived = false; } #endregion 方法 #region 重写 protected override void OnPaint(PaintEventArgs e) { if (_isActived && _isDrawing) { //抗锯齿 e.Graphics.SmoothingMode = SmoothingMode.HighQuality; using (var bmp = new Bitmap(200, 200)) { //缓冲绘制 using (Graphics bufferGraphics = Graphics.FromImage(bmp)) { //抗锯齿 bufferGraphics.SmoothingMode = SmoothingMode.HighQuality; foreach (Dot dot in _dots) { var rect = new RectangleF( new PointF(dot.Location.X - _dotSize / 2, dot.Location.Y - _dotSize / 2), new SizeF(_dotSize, _dotSize)); bufferGraphics.FillEllipse(new SolidBrush(Color.FromArgb(dot.Opacity, Color)), rect); } } //贴图 e.Graphics.DrawImage(bmp, new PointF(0, 0)); } //bmp disposed } base.OnPaint(e); } protected override void OnResize(EventArgs e) { Height = Width; _dotSize = Width / 12f; base.OnResize(e); } #endregion 重写 } }