Search This Blog

Saturday, April 23, 2011

A New Way to Disable a Form's Controls

[C# - WinForms]

I was working on a new project and I came across a re-occurring problem that has always annoyed the crap out of me; disabling all of the controls on a form when an operation is working in the background.

None of these standard methods really worked for me:

1) Form.Enabled = false
This not only causes all of the controls to be disabled but it also completely disabled the form and, most importantly, the ability to close the form.

2) Looping each control and disabling it
Not too bad but I was using themed controls on my form and some of them looked horrible when disabled. This was not going to work either.

3) Extending the Form class and disabling mouse and keyboard input when needed.
This wouldn't work because I needed, at the minimum, mouse input to cancel the background operation.

So, I decided to do something different. I created a custom control based off the Panel control to overlay the portion of the screen that I wanted "disabled" and made it take a quick snapshot of the screen underneath when it rendered.

I simply dropped the panel on my form, covered the area that I wanted to disable during the background operation, sent the panel to the back of the control hierarchy and set the visibility to false. Then, in my button's onclick event, I enabled the form's wait cursor and simply brought the panel to the front and turned the visibility on.

this.UseWaitCursor = true;
transparentPanel1.BringToFront();
transparentPanel1.Visible = true;

It worked great! I now have an easy way to disable my form without changing the appearance or writing a ton of code to disable and re-enable all of the controls.

Here is the code for the TransparentPanel
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Windows.Forms;

public partial class TransparentPanel : Panel
{   

 public TransparentPanel()
 {
  InitializeComponent();
 }

 public TransparentPanel(IContainer container)
 {
  container.Add(this);

  InitializeComponent();
 }

  
 protected override void OnPaintBackground(PaintEventArgs e)
 {
  Bitmap bgCache = new Bitmap(this.Width, this.Height);

  using (Graphics g = Graphics.FromImage(bgCache))
  {
   if (this.Parent == null || this.DesignMode)
   {
    //No parent or the control is in the designer.
    //Just paint the control normally
    g.FillRectangle(SystemBrushes.Control, 0, 0, this.Width, this.Height);
   }
   else
   {
    Point p2 = this.Parent.PointToScreen(this.Location);
    g.CopyFromScreen(p2.X, p2.Y, 0, 0, new Size(this.Width, this.Height));
   }
  }

  e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
  e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
  e.Graphics.InterpolationMode = InterpolationMode.High;
  e.Graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;

  e.Graphics.DrawImage(bgCache, 0, 0);   
 }
}

No comments:

Post a Comment