C#自定义加载框、等待框、加载层
自制简单实用加载层
1.主要方式就是通过graphics围绕中心点绘制N个小圆实现动态的效果,一圈之后变换颜色继续绘制。
主要用到graphics的TranslateTransform、RotateTransform方法,代码如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace FormLoading.Dialog { public enum EMLoadingType { Small, Middle, Large} public partial class FormLoading : BaseDialog { public Point ptOrigin = new Point(0, 0); private int offset = 30; private int angle = 0; private int ConstAngle = 36; private int CircleWidth = 20; private Pen pLight = new Pen(Color.LightBlue, 2f); private Brush bLight = new SolidBrush(Color.LightBlue); private Brush bDark = new SolidBrush(Color.SkyBlue); private EMLoadingType loadType = EMLoadingType.Middle; public bool Finished { get; set; } = false; public bool Success { get; set; } = false; public string ResultStr { get; set; } public FormLoading() { InitializeComponent(); } public void SetLoading(EMLoadingType type,string title,string tips) { ShowTips(tips); TitleText = title; loadType = type; } public void EndLoading(bool success) { tmLoading.Enabled = false; this.Finished = true; this.Success = success; if(this.Visible == true) this.Close(); } public void ShowTips(string tips) { labTips.Text = tips; } private void DrawCircle(Graphics g, Brush b, Pen p) { g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; RectangleF rectStart = new RectangleF(); rectStart.X = ptOrigin.X + offset; rectStart.Y = ptOrigin.Y - CircleWidth / 2; rectStart.Width = CircleWidth; rectStart.Height = CircleWidth; //g.DrawEllipse(p, rectStart); g.FillEllipse(b, rectStart); } private void tmLoading_Tick(object sender, EventArgs e) { Graphics g = this.pnlForm.CreateGraphics(); Brush b; if (angle > 720 - ConstAngle) angle = 0; if (angle <= 360 - ConstAngle) b = bLight; else b = bDark; g.TranslateTransform(Width / 2, Height / 2); g.RotateTransform(angle); DrawCircle(g, b, pLight); angle += ConstAngle; g.Dispose(); } private void btnSmall_Click(object sender, EventArgs e) { Start_SmallLoading(); } private void btnMiddle_Click(object sender, EventArgs e) { Start_MiddleLoading(); } private void btnLarge_Click(object sender, EventArgs e) { Start_LargeLoading(); } private void Start_SmallLoading() { tmLoading.Enabled = false; Graphics g = this.pnlForm.CreateGraphics(); g.Clear(SystemColors.Control); g.Dispose(); angle = 0; offset = 20; ConstAngle = 36; CircleWidth = 13; tmLoading.Enabled = true; } private void Start_MiddleLoading() { tmLoading.Enabled = false; Graphics g = this.pnlForm.CreateGraphics(); g.Clear(SystemColors.Control); g.Dispose(); angle = 0; offset = 30; ConstAngle = 36; CircleWidth = 20; tmLoading.Enabled = true; } private void Start_LargeLoading() { tmLoading.Enabled = false; Graphics g = this.pnlForm.CreateGraphics(); g.Clear(SystemColors.Control); g.Dispose(); angle = 0; offset = 40; ConstAngle = 36; CircleWidth = 25; tmLoading.Enabled = true; } private void FormLoading_Shown(object sender, EventArgs e) { labTips.BackColor = SystemColors.Control; switch (loadType) { case EMLoadingType.Small: Start_SmallLoading(); break; case EMLoadingType.Middle: Start_MiddleLoading(); break; case EMLoadingType.Large: Start_LargeLoading(); break; } } } }
效果图如下:
2. 上面只是实现了加载层的效果,具体使用需要调用相应方法用模态方式展示,并在后台用线程完成自己的耗时操作,然后关闭加载层,中间可以用invoke方法回显具体进度信息。方法如下:
//owner:主线程UIcontrol,Application.OpenForms["xxx"]就可以,param是线程处理自己的耗时业务参数
public static void DownLoadDataCallBack(Control owner, FormLoading loadingFrom, object param) { Action EndLoadingEvent; Action<string> ShowTipsEvent; bool success = false; string resultStr = ""; void ExecuteTrd() { //这里dataRlt采用Tuple返回<bool,string>两个返回结果方法好用! var dataRlt = DownloadXXXX(param); success = dataRlt.Item1; resultStr = dataRlt.Item2; owner.Invoke(EndLoadingEvent); } void EndLoading() { loadingFrom.ResultStr = resultStr; loadingFrom.EndLoading(success); } void SetTips(string tips) { loadingFrom.ShowTips(tips); } EndLoadingEvent = EndLoading; ShowTipsEvent = SetTips; if (loadingFrom != null && param != null) { Thread trd = new Thread(ExecuteTrd); trd.Start(); } }
3.下面是封装的弹出加载框方法,调用就可以显示。
/// <summary> /// 统一弹出加载框方法 /// </summary> /// <param name="owner">UI窗体</param> /// <param name="title">窗体名称</param> /// <param name="tips">加载显示信息</param> /// <param name="callBack">业务回调方法(耗时)</param> /// <param name="param">业务回调参数</param> /// <param name="type">加载圆大小</param> /// <returns></returns> public Tuple<bool,string> ShowLoadingTips(Control owner, string title, string tips, Action<Control, FormLoading, object> callBack, object param, EMLoadingType type = EMLoadingType.Middle) { Logger.Debug("ShowLoadingTips"); FormLoading loadingDialog = new FormLoading(); loadingDialog.SetLoading(type, title, tips); if(callBack != null) callBack(owner, loadingDialog, param); if(loadingDialog != null && !loadingDialog.Finished) loadingDialog.ShowDialog(); return new Tuple<bool, string>(loadingDialog.Success,loadingDialog.ResultStr); }
不错的业务耗时解决方案^_^。