Controls Inheriting Parent's Custom Drawing Code - winforms

I am trying to write an application that uses nested controls plus a Control.Paint event handler to draw a custom border. See the image below:
Notice how the "About ChocoTester" and "View version..." labels, as well as the PictureBox containing the icon, also draw the border (and, presumably, the background color as well, although that is not as immediately visible). I have added a Control.Paint event handler to the outermost box only. However, for some reason, the child controls are inheriting the Paint event code of the parent. I have never seen Windows Forms do this before until I started work on this project.
Note that the child controls have a BackColor of Transparent. This may or may not have anything to do with the symptoms described above. Also note that any child control of another control where the parent has a custom Paint event exhibits this behavior, be they standard Label instances or Panels with custom drawing code of their own.
Here is a sample Panel.Paint handler that exhibits this problem:
Rectangle r = e.ClipRectangle; r.Inflate(-1, -1);
e.Graphics.FillRectangle(Brushes.AliceBlue, r);
e.Graphics.DrawRectangle(Pens.DarkBlue, r);

I actually solved this on my own end. The problem was that I was using the PaintEventArgs.ClipRectangle to size the drawing. If I construct a Rectangle manually using Control.Width and Control.Height, and use that to draw to the screen, the behavior discussed above goes away.

Related

How do Transforms in WPF work?

I recently used a TranslateTransform in my WPF application to implement dragging a UserControl across the screen. There is a new bug in that after the first time you drag it somewhere else on the screen, when you click on the "Title bar" on the control, it jumps back to where it was originally displayed. It will still follow the mouse, but that initial jump is disconcerting.
I don't know what's going on, but this got me to wondering. Since WPF controls don't have a left or top property of their own, unless you put them into a Canvas, and those are attached properties anyway, just what properties are being modified by the TranslateTransform?
WPF's layout and render passes have intrinsic knowledge of transforms. By modifying the X and Y properties of the TranslateTransform, you're causing the layout/render pass to take those new values into consideration when positioning the associated FrameworkElement.
To put it another way: the TranslateTransform is not modifying other properties, but by modifying its properties you are triggering another layout/render pass and thus affecting the on-screen positioning of the associated FrameworkElement.
Read here for more information.

WPF Popup Alternative

I have a window with a popup that pops when an item in a listview is double clicked.
It centers to the main window and looks really nice floating there.
The problem is when the user moves the main window or selects another program, and the popup floats on top of other stuff.
I would like to have something like a popup, meaning that it floats on top of other elements in the window, but sticks with the main window when it moves (stays centered), and doesn't float on top of other programs.
Can I make a popup act like this, or is there a better way to do it?
Popups will not move while the window is resized or moved. Because, Popups/Context menus are not the part of Visual Tree. You have to use Adorner for this. I will suggest to read this four part series for a quick start on Adorner.
It's possible that an Adorner will fit your needs in this case better than a popup. Adorners can float above your window, too. There are a few differences, mainly that an adorner is bound to a UIElement (which include windows).
If you are willing to use a third-party/open source (MS-PL) option, the Extended WPF Toolkit has a ChildWindow control.
It's technically not a separate window, but it appears to be a separate window to the user.
I have not found a way to make Popups stop doing that in WPF
As an alternative, you can create a UserControl which acts like a Popup.
Usually I host the content section of the app along with the Popup within a Canvas control, and when IsPopupOpen gets changed to True I set the popup Visibility = Visible.

Transparent overlay which does not scroll with its parent

I would like to have a form which has a few controls as transparent overlays over a bitmap. This bitmap is subject to transform matrix (zoom & scroll). I'm trying to achieve a look similar to GoogleMaps where the controls do not move when the background image is panned/zoomed.
I've tried to mimic this in my OnPaint. However, when the window is scrolled only the newly exposed area gets invalidated so my control doesn’t repaint.
I've tried to calculate where the old control was, invalidate that area, and also invalidate the area where it's supposed to have been. When I do this it flickers and you can still see the image as its scrolled.
I tried to put a ButtonControl on my display window. However, it always scrolls with its parent control. I tried to capture the scroll events and then adjust the position of the ButtonControl. This also has a delay update effect so it looks not so good.
Any ideas would be greatly appreciated.
It sounds to me like you need to Invalidate() your control wich handles the OnPaint event.
Unfortunately, you get the flicker because the Auto-scrolling mechanism sets its position, and then you restore it. The result is two messages being sent to the button.
Place your bitmap and scroll logic in a separate control that fill the entire form. That means both your bitmap control and the button are child controls of the form.
Alternatively, draw the button yourself. You will then of course need to do some work on getting it to respond to mouse clicks etc. The ControlPaint class has methods that help you mimic the appearance of Windows controls.

C And Windows API: Changing Color Of Static Controls Which Are Child Of A Tab Control

I am trying to change the color of static controls that are child of a tab control. Now the thing is that, when I try to change it using WM_CTLCOLORSTATIC, it does not work.
When I define the main window as static's parent, it works fine. But how can I change the color while they are child of tab?
As David Heffernan says, when Visual Styles (themes) are enabled, the tab control has a fancy gradient-filled background. Since this only works when the child controls of the tab page have the same background, controls parented by tab controls actually have their backgrounds drawn by the parent.
Yep, it does not work with Themes. How do I make it work?
You don't, that's the whole point of Visual Styles. If you want this kind of fine-grained control over appearance, you should disable visual styles for your particular controls.
You can use the SetWindowTheme function to do this. Pass a handle to your control window as the first parameter and an empty string for the last two parameters:
SetWindowTheme(hwndCtrl, L" ", L" ");
Of course, you'll have to include uxtheme.h in order to call this function, and link to uxtheme.lib.
If you want your application to continue working on versions of Windows prior to XP (when the theming APIs were introduced), then you'll need to either use delay-loading or LoadLibrary and GetProcAddress to call the function dynamically.
You could also try calling the EnableThemeDialogTexture function and specifying the ETDT_DISABLE flag to disable the background texturing applied to tab dialogs.
Child controls send WM_CTLCOLORSTATIC to their parent. If you want the tab control to be parent of the static control, you need to subclass the tab control and handle WM_CTLCOLORSTATIC in there

How to achieve a transparent BackColor on an original WinForms control?

I'm about to lose my mind here.
Why won't the checkbox control blend with what's behind it?
The question applies to all WinForms controls, but I'm using this as an example.
A picture is worth a thousand words:
And a few more words:
What's behind the CheckBox are colored PictureBoxes and a Button.
The CheckBox's BackColor is set to Transparent. But somehow it decides that that means it should share the BackColor of the containing Form (is that its idea of the illusion of transparency?).
Is this not possible in WinForms? I could swear I did this before.
UPDATE:
I just tried this:
On that form, set the CheckBox's BackColor to Transparent, then change the BackColor of the containing Form to some other color, and the CheckBox will match that BackColor. What the.......?
This is a side effect of controls being Windows windows. A window is responsible for drawing itself, the OnPaintBackground and OnPaint methods take care of that.
This rendering model doesn't support transparency well. There is support for true transparency by using layered windows. That's implemented by the video adapter, Windows uses it hardware overlay feature. But that only works for toplevel windows, not child windows. Note the Form.Opacity and Form.TransparencyKey properties.
There's partial support for transparency through a trick. A control can fake it by asking the parent window to draw itself first inside the control window. That produces the background pixels, it can then draw on top of that. Setting the BackColor property to Color.Transparent enables this trick for controls that support this. All of the ButtonBase derived classes do. But not controls that are wrappers for native Windows controls.
"Asking the parent window" is where the flaw in this trick becomes visible in your screen shot. You are seeing the form pixels. Stacking effects don't work, it never considers any intermediary window in the Z-order, only the parent. This is fixable but very ugly, there's a KB article that show the code.
Also notable is that WPF doesn't have this restriction. Controls are not windows, they render by painting themselves on top of the parent. Layers of paint. Transparency is now trivial, just don't paint.
Bob Powell has written an excellent article about transparent controls. Check it out:
https://web.archive.org/web/20141227200000/http://bobpowell.net/transcontrols.aspx
Can you set the backcolor of the checkbox manually to the color you want? (The value in the picturebox behind it)
'Transparent' may mean something different from what you want to MS.
Also, try changing the zorder of the pictureboxes (bring to front) and see if that changes the checkbox's underlying color.

Resources