之前先后发表过:《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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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方法, 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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<objectobject> 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);
    }
}

使用示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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)

其余逻辑实现保持不变。

使用更简单,如下图示:

转载于:https://www.cnblogs.com/sjqq/p/6838548.html

Winform应用程序实现通用遮罩层二相关推荐

  1. Winform 通用遮罩层

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

  2. 微信小程序、vue遮罩层出现禁止穿透遮罩滚动页面

    vue <div class="detail-wrapper1" @touchmove.prevent> <div> 微信小程序解决方案 解决方案 无 滑动 ...

  3. # 解决微信小程序遮罩层底部页面滚动

    解决微信小程序遮罩层底部页面滚动 一.wxml文件添加catchtouchmove="move". <view class="" class=" ...

  4. 【微信小程序】小程序显示弹窗时禁止下层的内容滚动|遮罩层滚动穿透

    小程序显示弹窗时禁止下层的内容滚动|遮罩层滚动穿透 第一种方式 页面上加catchtouchmove="consume" JS // 把这个事件给消耗掉,这是是必须写的, 不写是可 ...

  5. [微信小程序]实现一个自定义遮罩层组件(完整示例代码附效果图)

    微信小程序开发交流qq群   173683895    承接微信小程序开发.扫码加微信. 正文: 先上效果图: 点击按钮Show显示遮罩层,再次点击屏幕任何地方隐藏遮罩层; <button bi ...

  6. 小程序 遮罩层(阻止事件穿透)

    小程序 遮罩层(阻止事件穿透) 若弹出层没有滚动事件 直接在蒙板上加catchtouchmove="preventTouchMove" 即可 <view class=&quo ...

  7. 微信小程序 原生开发 实现弹窗遮罩层 并且在遮罩层内使用scroll-view实现滚动内容(包括图片)

    微信小程序 原生开发 实现弹窗遮罩层 并且在遮罩层内可以滚动内容(包括图片) 效果图 这里的遮罩层内容由两张图片构成 底图+内部内容 实现代码 wxml 使用云开发的存储,自己开发的时候换掉src即可 ...

  8. android 遮罩 使底层无法点击,小程序防止点击遮罩层后遮罩层下面也反应(有点击事件)...

    小程序防止点击遮罩层后遮罩层下面也反应(有点击事件) 发布时间:2018-08-11 00:02, 浏览次数:1008 最近在做自定义弹窗,不免会使用到遮罩层或者说蒙层. 但是关键是,有遮罩层后,再点 ...

  9. php点击弹遮罩层,小程序:防止点击遮罩层后遮罩层下面也反应的解决方法

    本篇文章给大家带来的内容是关于小程序:防止点击遮罩层后遮罩层下面也反应的解决方法,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 最近在做自定义弹窗,不免会使用到遮罩层或者说蒙层. 但 ...

最新文章

  1. 15篇最新AI论文推荐新鲜出炉!真的很skr了~(附链接)
  2. 前驱、后驱和四驱,究竟哪个好?
  3. 干燥剂变身“配重剂”,究竟有多少商家在休闲零食市场浑水摸鱼?
  4. 路飞学城Python-Day9
  5. memcpy后数据不对_详解Redis 的 5 种基本数据结构:
  6. 得到application server上所有的logon user
  7. 【做题记录】[NOIP2016 普及组] 魔法阵
  8. Java对象垃圾回收调用,JVM垃圾回收之哪些对象可以被回收
  9. 关于Config.ARGB_8888、Config.ALPHA_8、Config.ARGB_4444、Config.RGB_565的理解
  10. Android-Device supports x86,but APK only supports armeabi-v7a,armeabi,x86_64
  11. Cisco Router WEB管理
  12. CentOS 8 基础命令
  13. python写鼠标宏_最全Pycharm教程(24)——Pycharm编辑器功能之宏定义
  14. c语言常用的100个程序,100个经典C语言程序,大家可以进来看看。
  15. 建立TCP连接的时候,syn包什么情况下会被对端rst?
  16. python3之微信文章爬虫
  17. 人面不知何处去,桃花依旧笑春风……
  18. 使用集成学习提升机器学习算法性能
  19. php基本变量,PHP-语法及变量基本操作
  20. docker安装过程 和部署2048小游戏

热门文章

  1. mybatis3.2.8 与 hibernate4.3.6 混用
  2. Linux学习记录--开机挂载错误
  3. Windows 2003 主域控和DNS迁移到Windows 2008 R2(2)
  4. 《那些年啊,那些事——一个程序员的奋斗史15》
  5. myeclipse10.7激活
  6. SHELL syntax error:unexpected end of file 提示错误
  7. 【正一专栏】巴萨耗光了所有的激情和精力
  8. (转载)java工程师15本必读书籍推荐
  9. 万字长文让你看够幂级数
  10. LaTeX 的对参考文献的处理