Winform应用程序实现通用遮罩层二

来源:互联网 发布:centos修改locale 编辑:程序博客网 时间:2024/06/03 17:11

之前先后发表过:《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上面的所有代码,即可测试出效果。

 

0 0
原创粉丝点击