在稍微复杂的交互应用中,避免不了耗时的操作,这时候总希望给用户明确的提示,表示程序在运行中暂时不能进行其他操作。显示一个半透明的处于等待状态的遮罩层是很好的方法。在Web应用程序中直接设置Div的透明度然后覆盖操作界面就好,但是Winform的好像并没有提供透明度之类的属性。
1.自定义控件类的实现
1 using System; 2 using System.ComponentModel; 3 using System.Drawing; 4 using System.Windows.Forms; 5 6 namespace WindowsFormsApplication1 7 { 8 9 /// <summary> 10 /// 透明的加载等待层 11 /// </summary> 12 [ToolboxBitmap(typeof(LoadingPanel))] 13 public class LoadingPanel : Control 14 { 15 #region Field 16 17 /// <summary> 18 /// 是否背景透明 19 /// </summary> 20 private bool _transparentBackGround = true; 21 22 /// <summary> 23 /// 透明度 24 /// </summary> 25 private int _alpha = 125; 26 27 /// <summary> 28 /// 容器组件 29 /// </summary> 30 private readonly Container _components = new Container(); 31 32 #endregion 33 34 #region Property 35 36 /// <summary> 37 /// 是否使用透明 38 /// </summary> 39 [Category("AlphaOpaque"), Description("是否使用透明,默认为True")] 40 public bool TransparentBackGround 41 { 42 get { return _transparentBackGround; } 43 set 44 { 45 _transparentBackGround = value; 46 this.Invalidate(); 47 } 48 } 49 50 /// <summary> 51 /// 设置透明度 52 /// </summary> 53 [Category("AlphaOpaque"), Description("设置透明度")] 54 public int Alpha 55 { 56 get { return _alpha; } 57 set 58 { 59 _alpha = value; 60 this.Invalidate(); 61 } 62 } 63 64 #endregion 65 66 #region Ctor 67 68 /// <summary> 69 /// 构造函数 70 /// </summary> 71 public LoadingPanel() : this(true) { } 72 73 /// <summary> 74 /// 标准构造函数 75 /// </summary> 76 /// <param name="showLoadingImage"></param> 77 public LoadingPanel(bool showLoadingImage) 78 { 79 SetStyle(ControlStyles.Opaque | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true); 80 81 base.CreateControl(); 82 // 显示等待的图像 83 if (showLoadingImage) 84 { 85 var pictureBoxLoading = new PictureBox(); 86 pictureBoxLoading.BackColor = Color.White; 87 pictureBoxLoading.Image = Properties.Resources.loding; 88 pictureBoxLoading.Name = "pictureBox_Loading"; 89 pictureBoxLoading.Size = new Size(48, 48); 90 pictureBoxLoading.SizeMode = PictureBoxSizeMode.Zoom; 91 var location = new Point(this.Location.X + (this.Width - pictureBoxLoading.Width) / 2, 92 this.Location.Y + (this.Height - pictureBoxLoading.Height) / 2); 93 pictureBoxLoading.Location = location; 94 pictureBoxLoading.Anchor = AnchorStyles.None; 95 this.Controls.Add(pictureBoxLoading); 96 } 97 } 98 99 #endregion 100 101 #region Override Method 102 103 /// <summary> 104 /// 自定义绘制窗体 105 /// </summary> 106 /// <param name="e"></param> 107 protected override void OnPaint(PaintEventArgs e) 108 { 109 Pen labelBorderPen; 110 SolidBrush labelBackColorBrush; 111 112 if (_transparentBackGround) 113 { 114 Color drawColor = Color.FromArgb(this._alpha, this.BackColor); 115 labelBorderPen = new Pen(drawColor, 0); 116 labelBackColorBrush = new SolidBrush(drawColor); 117 } 118 else 119 { 120 labelBorderPen = new Pen(this.BackColor, 0); 121 labelBackColorBrush = new SolidBrush(this.BackColor); 122 } 123 124 float controlWidth = this.Size.Width; 125 float controlHeight = this.Size.Height; 126 127 e.Graphics.DrawRectangle(labelBorderPen, 0, 0, controlWidth, controlHeight); 128 e.Graphics.FillRectangle(labelBackColorBrush, 0, 0, controlWidth, controlHeight); 129 130 base.OnPaint(e); 131 } 132 133 /// <summary> 134 /// 析构处理 135 /// </summary> 136 /// <param name="disposing"></param> 137 protected override void Dispose(bool disposing) 138 { 139 if (disposing) 140 { 141 if (_components != null) 142 { 143 _components.Dispose(); 144 } 145 } 146 base.Dispose(disposing); 147 } 148 149 #endregion 150 151 #region Public method 152 153 /// <summary> 154 /// 隐藏处理 155 /// </summary> 156 internal void CloseWaitingPanel() 157 { 158 this.BeginInvoke(new Action(() => 159 { 160 SendToBack(); 161 Hide(); 162 })); 163 } 164 165 /// <summary> 166 /// 显示处理 167 /// </summary> 168 internal void ShowWaitingPanel() 169 { 170 this.BeginInvoke(new Action(() => 171 { 172 BringToFront(); 173 Show(); 174 })); 175 } 176 177 #endregion 178 } 179 }
2.在窗体引用遮罩类达到理想的效果
namespace WindowsFormsApplication1 { public partial class Form1 : Form { private readonly LoadingPanel _loadingPanel; public Form1() { InitializeComponent(); _loadingPanel = new LoadingPanel(); } private void Form1_Load(object sender, EventArgs e) { _loadingPanel.Dock = DockStyle.Fill; _loadingPanel.Hide(); Controls.Add(_loadingPanel); } private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { Thread.Sleep(10 * 1000); } private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { _loadingPanel.CloseWaitingPanel(); } private void btnLoad_Click(object sender, EventArgs e) { if (!backgroundWorker1.IsBusy) { _loadingPanel.ShowWaitingPanel(); backgroundWorker1.RunWorkerAsync(); } } } }
可以参考实现的效果,当单击按钮时,遮罩层显示半透明样式显示以遮挡用户操作。当后台操作结果时,遮罩层消失,用户继续其他操作。