开发者

Problems with overriding OnPaint and grabbing mouse events in C# UserControl containing other controls

开发者 https://www.devze.com 2023-02-01 17:46 出处:网络
I\'ve made a control which contains few other controls like PictureBox, Label and TextBox. But I\'m having two problems:

I've made a control which contains few other controls like PictureBox, Label and TextBox. But I'm having two problems:

1. I tried to paint some things on top of my control and when I'm overriding OnPaint, it results that things I try to draw are under controls that my control contains. Areas on which I would like to draw intersect with controls in ways that are not easy to predict. I mean that it includes something drawn on controls inside as well as on base of control. Is there a simple way to draw something on top of all contents of my control? Setting ForeColor to Transparent isn't a solution that would help me much.

2. I have a problem with grabbing mouse click events when I place my control on a form and add click event handling. It only works when I click on an area not occupied by controls inside. I would like the whole control to react to clicks and other actions like it was one consistent control. How can I redirect/handle these clicks to make them work the way I want?

Thanks in advance for any tips

edit:

Thanks for answer, i hoped for something less complexed.开发者_如何学JAVA

Finally i decided to do it from scratch, painting all necessary things directly on surface of my UserControl, TextBox shows up only when it is necessary. That solved all of my problems with drawing and events.

MTH


1) Overriding a control's OnPaint event allows you to draw onto that control. Whenever that control is painted, your drawing code will be executed. Then, and only then, will the child controls be drawn on top of that control, each of them with their own OnPaint events executing. Each control is its own window (in the sense of the Windows API), and therefore each is responsible for drawing its own surface. This explains why your graphics are being covered up by the child controls, and why they are only visible in the empty spaces where no child controls have been placed.

The upshot is that drawing on top of multiple controls inside a container is not well-supported. There are a couple of hacks you could try to help get around these limitations, but you may well be disappointed.

The first possible hack is to draw your graphics on the container control as you've already done, and then also draw on top of the child controls themselves. You'll need to override each child control's OnPaint event in order for this to work, however, which immediately presents a problem. A TextBox control (along with a ComboBox, ListView, TreeView, and a handful of other controls) doesn't do its drawing in an OnPaint event; it's drawn natively by the operating system. The possible workarounds for this are so potentially painful that you might as well forget about it and change your design.

The second possible hack is to add another control that sits on top of the container control and do your drawing on its surface. Perhaps the easiest way to do this is by creating something like a transparent panel using the WS_EX_TRANSPARENT extended window style:

public class TransparentPanel : Panel
{
    protected override CreateParams CreateParams
    {
        get
        {
            const int WS_EX_TRANSPARENT = 0x00000020;

            CreateParams cp = base.CreateParams;
            cp.ExStyle |= WS_EX_TRANSPARENT
            return cp;
        }
    }

    protected override void OnPaintBackground(PaintEventArgs e)
    {
        //Do nothing
    }
}

2) Again, it becomes relevant that each child control is its own window and handles its own mouse input events. That's why the control whose MouseClick event you've overridden is only detecting the clicks that occur directly on its surface. The other clicks get passed to the child controls, who just ignore them. Events in WinForms are not bubbled up the control hierarchy.

As before, one possible solution is to handle the MouseClick event (and any others you want) for both the container and child controls. If you decide to go this route, I think I would recommend consolidating your logic into a single routine and simply calling that routine from each control's event handler.

If you're looking for something more comprehensive, you might check out Broadcasting Events through a Control Hierarchy, although I haven't taken the time to read it.

Of course, you could also send the relevant mouse input messages to your parent container control from each child control using the SendMessage API function. But I'll leave that as an exercise for the reader because I feel like you asked a simple question expecting a simple answer.

0

精彩评论

暂无评论...
验证码 换一张
取 消