Winform应用程序实现通用遮罩层二
之前先后發表過:《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<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); ????} } |
使用示例如下:
| 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应用程序实现通用遮罩层二的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用 pv 命令监控 linux 命令的
- 下一篇: 【转载】PHP面向对象(OOP)编程入门