之前先后发表过:《Winform应用程序实现通用遮罩层》、《Winform应用程序实现通用消息窗口》,这两款遮罩层其实都是基于弹出窗口的,今天为大家分享一个比较简单但界面相对友好的另一种实现方案,废话不多说,直接进入主题。

一、实现思路(解决问题顺序):

透明遮罩:

1.实现可设置透明的Panel控件(MaskPanel);

2.Panel控件(MaskPanel)能够覆盖父容器(一般是当前窗体form对象)客户区区域(即:与父容器客户区区域大小相同),并处于最上层,保证父容器上的任何控件都被盖住并保证不可用;

3.Panel控件(MaskPanel)必需实现随着父容器大小的改变而改变;

4.Panel控件(MaskPanel)上可呈现以表示正在加载的动图或者文字,并且居中;

异步:

实现的方法有很多,比如异步委托、Task等,而这是在winform项目中,此次就直接使用BackgroundWorker

二、关键解决方案:

1.可设置透明控件:通过自定义控件,并重写CreateParams(其中: cp.ExStyle |= 0x00000020;)、OnPaint(其中:labelBorderPen、labelBackColorBrush的Color=Color.FromArgb(_alpha, this.BackColor))两个方法即可;

2.能够覆盖父容器客户区区域:this.Size = this.Parent.ClientSize;this.Left = 0;this.Top = 0;

3.随着父容器大小的改变而改变:this.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom;

4.呈现以表示正在加载的动图或者文字,并且居中:

添加PictureBox,设置Image为loading.gif动图,SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize; Point Location = new Point(this.Location.X + (this.Width - pictureBox_Loading.Width) / 2, this.Location.Y + (this.Height - pictureBox_Loading.Height) / 2);//居中

好了,最后贴出实现的源代码:

MaskPanel:

    public partial class MaskPanel : Control
{
private System.ComponentModel.Container components = new System.ComponentModel.Container(); private bool _isTransparent = true;//是否透明
[Category("透明"), Description("是否使用透明,默认为True")]
public bool IsTransparent
{
get { return _isTransparent; }
set { _isTransparent = value; }
} private int _alpha = 125;//设置透明度
[Category("透明"), Description("设置透明度")]
public int Alpha
{
get { return _alpha; }
set { _alpha = value; }
} public MaskPanel(Control parent)
: this(parent, 125)
{ } /// <summary>
/// 初始化加载控件
/// </summary>
/// <param name="Alpha"透明度</param>
public MaskPanel(Control parent, int alpha)
{
SetStyle(ControlStyles.Opaque, true);//设置背景透明
base.CreateControl();
_alpha = alpha;
parent.Controls.Add(this);
this.Parent = parent;
this.Size = this.Parent.ClientSize;
this.Left = 0;
this.Top = 0;
this.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom;
this.BringToFront(); PictureBox pictureBox_Loading = new PictureBox();
pictureBox_Loading.BackColor = System.Drawing.Color.Transparent;
pictureBox_Loading.Image = Properties.Resources.loading;
pictureBox_Loading.Name = "pictureBox_Loading";
pictureBox_Loading.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
Point Location = new Point(this.Location.X + (this.Width - pictureBox_Loading.Width) / 2, this.Location.Y + (this.Height - pictureBox_Loading.Height) / 2);//居中
pictureBox_Loading.Location = Location;
pictureBox_Loading.Anchor = AnchorStyles.None;
this.Controls.Add(pictureBox_Loading); this.Visible = false;
} protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x00000020; // 开启 WS_EX_TRANSPARENT,使控件支持透明
return cp;
}
} protected override void OnPaint(PaintEventArgs pe)
{
Pen labelBorderPen;
SolidBrush labelBackColorBrush;
if (_isTransparent)
{
Color cl = Color.FromArgb(_alpha, this.BackColor);
labelBorderPen = new Pen(cl, 0);
labelBackColorBrush = new SolidBrush(cl);
}
else
{
labelBorderPen = new Pen(this.BackColor, 0);
labelBackColorBrush = new SolidBrush(this.BackColor);
}
base.OnPaint(pe);
pe.Graphics.DrawRectangle(labelBorderPen, 0, 0, this.Width, this.Height);
pe.Graphics.FillRectangle(labelBackColorBrush, 0, 0, this.Width, this.Height);
} protected override void Dispose(bool disposing)
{
if (disposing)
{
if (!((components == null)))
{
components.Dispose();
}
}
base.Dispose(disposing);
} }

为了实现通用,同时保证所有的窗体都有异步执行并显示遮罩效果,故此处采用定义一个窗体基类:FormBase,里面定义一个受保护的DoWorkAsync方法, 代码如下:

    public partial class FormBase : Form
{
public FormBase()
{
InitializeComponent();
this.StartPosition = FormStartPosition.CenterParent;
} /// <summary>
/// 多线程异步后台处理某些耗时的数据,不会卡死界面
/// </summary>
/// <param name="workFunc">Func委托,包装耗时处理(不含UI界面处理),示例:(o)=>{ 具体耗时逻辑; return 处理的结果数据 }</param>
/// <param name="funcArg">Func委托参数,用于跨线程传递给耗时处理逻辑所需要的对象,示例:String对象、JObject对象或DataTable等任何一个值</param>
/// <param name="workCompleted">Action委托,包装耗时处理完成后,下步操作(一般是更新界面的数据或UI控件),示列:(r)=>{ datagirdview1.DataSource=r; }</param>
protected void DoWorkAsync(Func<object, object> workFunc, object funcArg = null, Action<object> workCompleted = null)
{
var bgWorkder = new BackgroundWorker(); //Form loadingForm = null;
Control loadingPan = null;
bgWorkder.WorkerReportsProgress = true;
bgWorkder.ProgressChanged += (s, arg) =>
{
if (arg.ProgressPercentage > 1) return; #region Panel模式 var result = this.Controls.Find("loadingPan", true);
if (result == null || result.Length <= 0)
{
loadingPan = new MaskPanel(this)
{
Name = "loadingPan"
};
}
else
{
loadingPan = result[0];
} loadingPan.BringToFront();
loadingPan.Visible = true; #endregion
}; bgWorkder.RunWorkerCompleted += (s, arg) =>
{ #region Panel模式 if (loadingPan != null)
{
loadingPan.Visible = false;
} #endregion bgWorkder.Dispose(); if (workCompleted != null)
{
workCompleted(arg.Result);
}
}; bgWorkder.DoWork += (s, arg) =>
{
bgWorkder.ReportProgress(1);
var result = workFunc(arg.Argument);
arg.Result = result;
bgWorkder.ReportProgress(100);
}; bgWorkder.RunWorkerAsync(funcArg);
} }

使用示例如下:

        private void button1_Click(object sender, EventArgs e)
{
int startNo = 20;
button1.Enabled = false;
this.DoWorkAsync((o) => //耗时逻辑处理(此处不能操作UI控件,因为是在异步中)
{
int result = 0;
for (int i = 1; i <= Convert.ToInt32(o); i++)
{
result += i;
Thread.Sleep(500);
}
return result; }, startNo, (r) => //显示结果(此处用于对上面结果的处理,比如显示到界面上)
{
label1.Text = r.ToString();
button1.Enabled = true;
}); }

效果图就不贴出来了,大家可以COPY上面的所有代码,即可测试出效果。

2017年3月15日优化补充:

为了提高异步加载编码的方便,特优化了DoWorkAsync方法,将返回值由object改为dynamic,这样就比较方便,直接返回,直接使用

方法签名如下:

protected void DoWorkAsync(Func<object, dynamic> workFunc, object funcArg = null, Action<dynamic> workCompleted = null)

其余逻辑实现保持不变。

使用更简单,如下图示:

Winform应用程序实现通用遮罩层二的更多相关文章

  1. Winform应用程序实现通用遮罩层

    在WEB上,我们在需要进行大数据或复杂逻辑处理时,由于耗时较长,一般我们会在处理过程中的页面上显示一个半透明的遮罩层,上面放个图标或提示:正在处理中...等字样,这样用户体验就比较好了,然而如果在Wi ...

  2. Winform应用程序实现通用消息窗口

    记得我之前发表过一篇文章<Winform应用程序实现通用遮罩层>,是实现了透明遮罩的消息窗口,功能侧重点在动图显示+消息提醒,效果看上去比较的炫,而本篇我又来重新设计通用消息窗口,功能重点 ...

  3. WinForm特效:桌面上的遮罩层

    一个窗体特效,帮你了解几个windows api函数.效果:windows桌面上增加一个简单的遮罩层,其中WS_EX_TRANSPARENT 比较重要,它实现了鼠标穿透的功能. using Syste ...

  4. HTML 弹出遮罩层二(遮罩层和内容标签分开)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. [C#] (原创)一步一步教你自定义控件——06,MaskLayer(遮罩层)

    一.前言 技术没有先进与落后,只有合适与不合适. 本篇的自定义控件是:遮罩层(MaskLayer). 遮罩层对软件的美观与易用性上的提高是很大的,在日常使用过程中也会经常看到各种遮罩层,虽然WinFo ...

  6. 微信小程序遮罩层覆盖input失效

    问题:微信小程序中,我们常使用遮罩层,如点击按钮弹出下拉框.弹框等等.若在遮罩层下存在input.textarea.canvas.camera.map.video等标签时,会出现遮罩层覆盖失效的问题. ...

  7. C# Winform 实现自定义半透明loading加载遮罩层

    在网页中通过div+css实现半透明效果不难,今天我们看看一种在winfrom中实现的方法: 效果图如下,正常时: 显示遮罩层时: 自定义遮罩层控件的源码如下: View Row Code 1 usi ...

  8. 微信小程序弹出和隐藏遮罩层动画以及五星评分

    参考源码: http://www.see-source.com/weixinwidget/detail.html?wid=82 https://blog.csdn.net/pcaxb/article/ ...

  9. C# Winform 实现自定义半透明遮罩层介绍

    在网页中通过div+css实现半透明效果不难,今天我们看看一种在winfrom中实现的方法: 效果图如下,正常时: 显示遮罩层时: 自定义遮罩层控件的源码如下: View Row Code 1 usi ...

随机推荐

  1. 【NOIP2015提高组】运输计划

    https://daniu.luogu.org/problem/show?pid=2680 使完成所有运输计划的时间最短,也就是使时间最长的运输计划耗时最短.最大值最小问题考虑用二分答案,每次chec ...

  2. RandomAccessFile详解

    此类的实例支持对随机访问文件的读取和写入.随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组.存在指向该隐含数组的光标或索引,称为文件指针:输入操作从文件指针开始读取字节,并随着对字节的 ...

  3. ps的快捷键

    最近学习了一些ps切图,总结一些快捷键,以免自己忘记,总结的不好,也可能不全,忘大牛指点,试着坚持总结 1.工具箱 (多种工具共用一个快捷键的可同时按[Shift]加此快捷键选取) 矩形.椭圆选框工具 ...

  4. Android调用系统自带的文件管理器进行文件选择

    http://blog.csdn.net/zqchn/article/details/8770913的补充 FileUtils文件 public class FileUtils {     publi ...

  5. WPF使用RoutedCommand自己定义命令

    主要代码例如以下所看到的: /// <summary> /// 声明并定义命令. /// </summary> RoutedCommand ClearCommand = new ...

  6. 基于FPGA的图像显示

    基于FPGA的图像显示 作者:lee神 这几天一直在调试FPGA的图像显示系统,今天终于成功,图像不在闪烁,也不再边框缺失. 基于FPGA的图像处理的第一课应该是基于FPGA的图像显示,只有图像正常显 ...

  7. F02 金融学第二定律 资金的积聚

    美国南北战争,北方取胜的关键在于发行了债券,从而积聚了资金,提升了北方军队战斗力. 纽约的逆袭,得益于伊利运河的修建,而伊利运河的建造需要的资金,全靠债券发行积聚的资金. 聚积起来的资金,往往决定了重 ...

  8. 自学Zabbix3.10.1.3-事件通知Notifications upon events-媒介类型Jabber

    自学Zabbix3.10.1.3-事件通知Notifications upon events-媒介类型Jabber Jabber有第三方插件,能让Jabber用户和MSN.YahooMessager. ...

  9. 分组查询限制。HAVING可写在GROUP BY前。

    限制一.无GROUP BY时统计函数不能和字段同时出现: 限制二.有GROUP BY时字段部分只能出现分组的字段: 限制三.统计函数嵌套时不能有字段.

  10. 关于table布局的推荐使用原因

    一.关于table布局的性能 1.table标签比其他html标签占用更多字节,导致下载时间延迟,占用服务器更多的流量资源: 2.table会阻碍浏览器渲染引擎的渲染顺序,导致页面生成的延迟,造成不良 ...