Groups | Blog | Home
all groups > dotnet drawing api > september 2005 >

dotnet drawing api : UserControl WM_PRINTCLIENT problem


Oliver Sturm
9/8/2005 12:00:00 AM
[quoted text, click to view]

It should definitely work with PRF_CHILDREN. I have only recently done it
for a sample that's on my blog - see
http://www.sturmnet.org/blog/archives/2005/08/26/explorer-rubber-band2/ -
the sample code in the comment down at the bottom has the set of flags I
was using.


Oliver Sturm
--
Expert programming and consulting services available
See http://www.sturmnet.org (try /blog as well)
MariusI
9/8/2005 6:30:05 AM
I'm trying to use WM_PRINTCLIENT to paint the client area of a usercontrol to
a bitmap. However, the controls encapsulated by the usercontrol are not
painted, only the client background which the contained controls are painted
on. I've tried using PRF_CHILDREN, PRF_CLIENT and also PRF_OWNED but the
MariusI
9/8/2005 9:55:03 AM
Thanks i''ll try that tomorrow. Since your obviously a man of great
knowledge, perhaps you can answer another thing that bugs me. The OnPaint
method is not responsible for drawing contained controls, and according to my
tests, the WM_PAINT message sent to the parent does not trigger a
corresponding WM_PAINT event on the contained controls. I tried to block the
WM_PAINT message sent to a container control to see if its child controls
still painted, and they did. According to my knowledge, there is only on
message queue which dispatch messages to the focused window. Does this mean
that you cannot control painting of child control through their container?
You see, i'm having trouble with flickering child controls when i resize the
parent control. My idea was to use the WM_PRINTCLIENT to draw everything to a
buffer between BeginPaint and EndPaint, before finally painting to screen.
[quoted text, click to view]
MariusI
9/8/2005 11:06:02 AM
The reason i got into low level stuff in the first place was that i wanted to
reserve space in a controls nc-area and then use that space to draw my own
fancy looking borders. So i started handing WM_NCCALCSIZE (both with wparam=0
(RECT) and wparam != 0 (NCCALCSIZE). My next task was to draw the non-client
borders with round corners and in some areas with lower alpha than 255 (to
create a smooth transition between the corners and the background).
Unfortunately, Windows does not handle true transparency very good (you'll
end up seeing through to the underlying desktop in transparent areas), so my
buest guess was to change the control region (didn't fix my
semi-transparency, but atleast i got round corners). Not i got a new problem,
because WM_NCPAINT was posted earlier than WM_SIZE when resizing the control,
the control region was not properly sized, and the nc area got clipped when i
tried to paint it. To counter this, i had to handle the WM_WINDOWPOSCHANGING,
marshal out the WINDOWPOS structure and utilize the given bounds to update
the control region prior to any WM_NCPAINT messages. Now, as i mentioned my
control can be moved and resized at runtime. The only way i got this to work
was to handle WM_NCHITTEST and manipulate the message return value to tell
the operaing system my intentions. This is the main reasons for going
low-level, if anyone can tell me to do the exact same things simple and
managed, i would love to hear it. Regards, marius

[quoted text, click to view]
MariusI
9/8/2005 1:06:03 PM
Ok, that sounds reasonable, but my control works as a base control, meaning
that the deriving control should put whatever they like within, and they
should still get the cool nc-area. How does your approach work in terms of
properties such as Bounds and ClientArea? The ClientArea (or rectangle i
can't remember the name from where i'm sitting now :-) ) are not virtual, so
how do you override them to return the ClientArea you want instead of the
whole window rectangle? Can you ovveride the properties using the new
operator, and in that case will that ensure that the base clase version of
the ClientArea is newer called? I can send you a picture from work tomorrow
showing you how my control looks and feels.

[quoted text, click to view]
Oliver Sturm
9/8/2005 6:25:09 PM
[quoted text, click to view]

I reckon you have overridden WndProc to receive the messages for your
control. In addition to that, you could install a message filter that
would let you have access to messages that are destined for other controls
than your own, like your child controls. See the IMessageFilter docs in
MSDN for more information about this.

That said, I don't really believe your problems with flickering child
controls should have much to do with what you're doing in the parent
control. Talking about that blog post I told you about - there are two
versions of that one online, the older one is here:
http://www.sturmnet.org/blog/archives/2005/08/26/explorer-rubber-band/

In this older version, the rubber band selection didn't draw itself in
front of child controls, if there were any there, but I'm sure it did that
without any flickering whatsoever. Try it - it looks interesting how the
rectangle you're dragging appears smoothly behind any controls you have on
the form.

I guess it's possible that you're doing some drawing that actually draws
*over* the child controls somehow, so the flickering you're seeing might
be the child controls restoring their visual state.

A last thing - you seem to be doing an awful lot of low level stuff in
your control. In my experience, this isn't usually necessary when creating
custom controls in .NET. Maybe you could post a more detailed description
of what exactly you want to achieve, so that somebody else can suggest
ways of doing it; I imagine you might find that there are easier ways to
do the same things.


Oliver Sturm
--
Expert programming and consulting services available
See http://www.sturmnet.org (try /blog as well)
Oliver Sturm
9/8/2005 7:21:22 PM
[quoted text, click to view]

Okay. I have a popup window in my tool box that does most of the same
things, and I only handle WM_NCHITTEST in my own WndProc. I'm not saying
it's intrinsically better, but it's a lot simpler in many ways. Of course,
I don't know about the specific problems you have encountered.

The main difference is, I don't do any handling of the standard NC area. I
simply show the window without any border and draw my stuff on it. Then I
respond to the WM_NCHITTEST and tell Windows it has found NC stuff when
the mouse is over the elements in my window: like resize borders or the
title bar. So I don't have any problems with WM_NCPAINT or WM_NCCALCSIZE
(and WM_WINDOWPOSCHANGING or WINDOWPOS as a result), because I don't need
them. I do use my own control region, which works just fine.


Oliver Sturm
--
Expert programming and consulting services available
See http://www.sturmnet.org (try /blog as well)
Oliver Sturm
9/9/2005 9:27:46 AM
[quoted text, click to view]

Good questions - currently I don't care. My popup window is used as a base
control, just as a normal form is, but I don't take any precautions to
prevent the user from putting controls in places they shouldn't. As this
control isn't used "externally", this hasn't been a problem for me.

About using "new" to hide the properties: while that approach would work
"from the top", meaning from the way the child controls or the derived
class looks at your control, many of the layout related properties of the
UserControl are used by base class code to perform the layout, handle the
scaling, things like that. From the view of a base class, the "new" method
or property is meaningless, so it wouldn't be used.

If I find the time, I might give my control a tryout to see if I can make
it behave, assuming someone wants to abuse it in a derived class :-) But
who knows, for that kind of complex scenario you might have found a very
good approach already.


Oliver Sturm
--
Expert programming and consulting services available
See http://www.sturmnet.org (try /blog as well)
AddThis Social Bookmark Button