前言
大家好,今天我们将探讨如何在 WinForm 客户端程序中实现一个类似 Web 端的"通用遮罩层"。在 Web 开发中,当进行大数据处理或复杂逻辑运算时,我们通常会使用一个半透明的遮罩层,配合动态图标和提示文字(如"正在处理中..."),以提升用户体验。然而,在传统的 WinForm 应用中,这种效果往往难以实现,或实现后不够美观。
本文将详细介绍一种在 WinForm 中实现透明遮罩层、动态图标显示与文字提示的完整方案,帮助大家打造更专业、更友好的桌面应用界面。
遮罩层效果预览
遮罩层覆盖主界面,显示动态加载图标和提示文字,任务完成后自动关闭,用户体验显著提升。
遮罩层的核心功能
我们希望实现的遮罩层具备以下三个核心特性:
1、透明效果:遮罩层应为半透明,既能覆盖主界面防止用户误操作,又能让用户隐约看到后台内容。通过设置窗体的 Opacity 属性(本文采用 85%)即可轻松实现。
2、动态图标:WinForm 原生控件不支持直接播放 GIF 动画。为此,我们利用 .NET 提供的 ImageAnimator 类,通过逐帧渲染的方式实现动图播放。
3、文字提示:使用 Label 控件显示提示信息,并确保文字与动图在任何窗体大小下都能居中显示。
为了实现布局的灵活性与居中对齐,我们采用 TableLayoutPanel 控件,将其分为两行:
-
上行放置
Label,用于显示提示文字。 -
下行放置
Panel,作为动图的绘制区域。
代码实现与使用方法
核心遮罩窗体 FrmProcessing
以下是实现遮罩层功能的完整代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
namespace TEMS
{
public partial class FrmProcessing : Form
{
private static Image m_Image = null;
private EventHandler evtHandler = null;
private ParameterizedThreadStart workAction = null;
private object workActionArg = null;
private Thread workThread = null;
public string Message
{
get
{
return lbMessage.Text;
}
set
{
lbMessage.Text = value;
}
}
public bool WorkCompleted = false;
public Exception WorkException
{ get; private set; }
public void SetWorkAction(ParameterizedThreadStart workAction, object arg)
{
this.workAction = workAction;
this.workActionArg = arg;
}
public FrmProcessing(string msg)
{
InitializeComponent();
this.Message = msg;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (m_Image != null)
{
// 获得当前gif动画下一步要渲染的帧。
UpdateImage();
// 将动图绘制在Panel上
int x = (int)(panImage.ClientRectangle.Width - m_Image.Width) / 2;
int y = 0;
panImage.CreateGraphics().DrawImage(m_Image, new Rectangle(x, y, m_Image.Width, m_Image.Height));
}
if (this.WorkCompleted)
{
this.Close();
}
}
private void FrmProcessing_Load(object sender, EventArgs e)
{
if (this.Owner != null)
{
this.StartPosition = FormStartPosition.Manual;
this.Location = new Point(this.Owner.Left, this.Owner.Top);
this.Width = this.Owner.Width;
this.Height = this.Owner.Height;
}
else
{
Rectangle screenRect = Screen.PrimaryScreen.WorkingArea;
this.Location = new Point((screenRect.Width - this.Width) / 2, (screenRect.Height - this.Height) / 2);
}
// 初始化动画事件
evtHandler = new EventHandler(OnImageAnimate);
if (m_Image == null)
{
Assembly assy = Assembly.GetExecutingAssembly();
// 加载嵌入资源中的GIF动图
m_Image = Image.FromStream(assy.GetManifestResourceStream(assy.GetName().Name + ".Resources.loading2.gif"));
}
// 开始动画
BeginAnimate();
}
// 开始动画
private void BeginAnimate()
{
if (m_Image != null)
{
ImageAnimator.Animate(m_Image, evtHandler);
}
}
// 动画触发时重绘窗体
private void OnImageAnimate(Object sender, EventArgs e)
{
this.Invalidate();
}
// 更新动画帧
private void UpdateImage()
{
ImageAnimator.UpdateFrames(m_Image);
}
private void FrmProcessing_Shown(object sender, EventArgs e)
{
if (this.workAction != null)
{
workThread = new Thread(ExecWorkAction);
workThread.IsBackground = true;
workThread.Start();
}
}
// 执行耗时任务
private void ExecWorkAction()
{
try
{
var workTask = new Task((arg) =>
{
this.workAction(arg);
}, this.workActionArg);
workTask.Start();
Task.WaitAll(workTask);
}
catch (Exception ex)
{
this.WorkException = ex;
}
finally
{
this.WorkCompleted = true;
}
}
}
}
注意:代码中未重写
Panel的OnPaint方法,是因为局部重绘会导致动图闪烁。因此采用窗体重绘(Invalidate())来避免闪屏问题。
通用调用方法
为了便于在项目中复用,我们封装了一个静态方法 Common.ShowProcessing:
public static class Common
{
public static void ShowProcessing(string msg, Form owner, ParameterizedThreadStart work, object workArg = null)
{
FrmProcessing processingForm = new FrmProcessing(msg);
dynamic expObj = new ExpandoObject();
expObj.Form = processingForm;
expObj.WorkArg = workArg;
processingForm.SetWorkAction(work, expObj);
processingForm.ShowDialog(owner);
if (processingForm.WorkException != null)
{
throw processingForm.WorkException;
}
}
}
使用方式
只需一行代码即可调用遮罩层:
Common.ShowProcessing("正在处理中,请稍候...", this, (obj) =>
{
// 在此处编写耗时的业务逻辑
// 例如:数据处理、文件读写、网络请求等
}, null);
总结
本文介绍了一种在 WinForm 中实现通用遮罩层的完整解决方案,具备以下优势:
-
高复用性:通过封装静态方法,可在任意窗体中一键调用。
-
良好体验:半透明遮罩 + 动态图标 + 文字提示,媲美 Web 端效果。
-
线程安全:耗时任务在后台线程执行,避免界面卡顿。
-
自动关闭:任务完成后自动销毁遮罩窗体,无需手动管理。
该方案特别适用于数据导入、报表生成、批量处理、网络请求等耗时操作场景。开发者可直接复制代码集成到项目中,快速提升应用的专业度与用户体验。
关键词
WinForm、遮罩层、透明窗体、GIF动画、ImageAnimator、OnPaint、异步处理、用户体验、通用组件、C#
最后
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。
也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!
优秀是一种习惯,欢迎大家留言学习!
作者:梦在旅途
出处:cnblogs.com/zuowj/p/4431856.html
声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!