自制简单实用加载层
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);
}
不错的业务耗时解决方案^_^。