By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,217 Members | 1,300 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,217 IT Pros & Developers. It's quick & easy.

C# application - system transparent control inside user drawn control...

P: 2
This one's a hairy one to explain. What I've got is a class called "VistaGroupBox" that I put some nice-looking Vista-style gradients in the background and made to look like the ribbon categories you see in Office 2007. I got it working great, and created a few more controls, including a "VistaButton", which is primarily transparent when the cursor does not hover over it. However, when I added a standard Panel in the VistaGroupBox and put my button inside the Panel (I want the Panel to auto-scroll), the VistaButton's transparent background started as though it were in the upper-left-hand corner of the VistaGroupBox, which was not where the button actually was at all! The button draws correctly when outside the Panel.

So, what I've got is this:
Expand|Select|Wrap|Line Numbers
  1. VistaGroupBox
  2.  +-Panel
  3.     +-VistaButton
In order to draw my transparent controls, I've made a function that does this: (Some controls, like Button, don't have transparency support at all - I got this from the Mono implementation)
Expand|Select|Wrap|Line Numbers
  1.         public delegate void InvokePaintDelegate(Control c, PaintEventArgs e);
  2.         public delegate void InvokePaintBackgroundDelegate(Control c, PaintEventArgs e);
  3.         /// <summary>
  4.         /// This function looks like a mess primarily because of the #if ... #endifs.  The problem is, the "BROKEN WINDOWS"
  5.         /// section is how WINDOWS does it, which is a problem for going through multiple transparent areas for whatever reason.
  6.         /// MY_CORRECT works if you're only going from user drawn transparency to user drawn transparency - that is, none of your
  7.         /// controls use Control.OnPaintBackground (like a Transparent Panel).  WINDOWS_HACK works in all conditions - too bad it uses
  8.         /// a bit more memory due to the image creation.
  9.         /// </summary>
  10.         /// <param name="c">The control to paint the parent to</param>
  11.         /// <param name="pevent">The PaintEventArgs from the OnPaintBackground call</param>
  12.         /// <param name="InvokePaint">The control's InvokePaint method - because it is protected.</param>
  13.         /// <param name="InvokePaintBackground">The control's InvokePaintBackground method - because it is protected.</param>
  14.         public static void DrawParent(Control c, PaintEventArgs pevent, InvokePaintDelegate InvokePaint, InvokePaintBackgroundDelegate InvokePaintBackground)
  15.         {
  16.             PaintEventArgs parent_pe;
  17.             GraphicsState state;
  18.             Rectangle clipRect;
  19.  
  20.             Graphics g;
  21. #if BROKEN_WINDOWS
  22.             IntPtr hdc = pevent.Graphics.GetHdc();
  23.             g = Graphics.FromHdc(hdc);
  24.             if (c.Region != null)
  25.                 g.Clip = c.Region;
  26.             else
  27.                 g.Clip = new Region(c.ClientRectangle);
  28.             clipRect = new Rectangle(pevent.ClipRectangle.X + c.Left, pevent.ClipRectangle.Y + c.Top, pevent.ClipRectangle.Width, pevent.ClipRectangle.Height);
  29. #elif MY_CORRECT
  30.             g = pevent.Graphics;
  31.             clipRect = new Rectangle(pevent.ClipRectangle.X + c.Left, pevent.ClipRectangle.Y + c.Top, pevent.ClipRectangle.Width, pevent.ClipRectangle.Height);
  32. #elif WINDOWS_HACK
  33.             Image img = new Bitmap(c.Parent.Width, c.Parent.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
  34.             g = Graphics.FromImage(img);
  35.             clipRect = new Rectangle(c.Location, c.Size);
  36.             g.Clip = new Region(clipRect);
  37. #endif
  38.  
  39.             parent_pe = new PaintEventArgs(g, clipRect);
  40.  
  41.             state = g.Save();
  42. #if !WINDOWS_HACK
  43.             g.TranslateTransform(-c.Left, -c.Top);
  44. #endif
  45.             InvokePaintBackground(c.Parent, parent_pe);
  46.             g.Restore(state);
  47.  
  48.             state = g.Save();
  49. #if !WINDOWS_HACK
  50.             g.TranslateTransform(-c.Left, -c.Top);
  51. #endif
  52.             InvokePaint(c.Parent, parent_pe);
  53.             g.Restore(state);
  54.  
  55. #if BROKEN_WINDOWS
  56.             g.Dispose();
  57.             pevent.Graphics.ReleaseHdc(hdc);
  58. #elif WINDOWS_HACK
  59.             g.Dispose();
  60.             pevent.Graphics.DrawImage(img, new Rectangle(new Point(0,0), c.Size), new Rectangle(c.Location, c.Size), GraphicsUnit.Pixel);
  61.             img.Dispose();
  62. #endif
  63.         }
  64.  
You can see that I've got 3 preprocessor directives here, each should be used exclusively. BROKEN_WINDOWS behaves exactly like the Windows default, WINDOWS_HACK works properly, except I'm creating images, and so it tends to be a bit slow.

Anyone got some time to help me figure this one out?
Sep 30 '07 #1
Share this question for a faster answer!
Share on Google+

Post your reply

Sign in to post your reply or Sign up for a free account.