0

I have a class which inherits the Panel Control, whose purpose is to allow me to draw some simple geometrical figures on a transparent background. The object is defined as follows:

 public class TrackOverlay : Panel
{
    private ControlWindow parentForm;
    ...
    public TrackOverlay(PictureBox parent)
    {
        parentForm = (ControlWindow)(parent.Parent);
        // Create a transparent form on top of <parent>
        ...
        this.Size = parent.ClientSize;
        this.Location = parent.PointToScreen(Point.Empty);
        parent.Parent.Controls.Add(this);
}

When a certain event occurs (in the context of a BackgroundWorker, if that matters) I call the Invalidate method, and expect to enter the following overridden Paint method, defined as follows:

new private void Paint(object sender, PaintEventArgs e)
    {
        using (Graphics graphics = this.CreateGraphics())
        {
          // do graphics stuff
        }
    }

Using the debugger, I see that Invalidate() is called, but Paint() is not This seems to be similar to the situation described here, but none of the suggestions mentioned there helped me. Following this post I redefined the function signature as follows:

protected override void OnPaint(PaintEventArgs e)

But still no joy. How can I make the event handler happen?

Community
  • 1
  • 1
Aharon Manne
  • 712
  • 3
  • 11
  • 34
  • What does `new private void Paint(object sender, PaintEventArgs e)` do? Did you mean `protected override void OnPaint(PaintEventArgs e)`? – bokibeg Dec 15 '15 at 13:03

2 Answers2

2
   parent.Parent.Controls.Add(this);

This does not do what you think it does. Your overlay doesn't overlay anything, it is underneath the PictureBox. So your OnPaint() method never gets called, there isn't any need to paint since the user can't see it anyway.

Not the only problem, you also won't get the transparency you hope for. You'll see the form through the transparent parts, not the image in the picture box. You must make the picturebox the parent instead. In other words:

   this.Location = Point.Empty;
   parent.Controls.Add(this);
   parent.Controls.SetChildIndex(this, 0);

The last line surely isn't actually needed but shows how you ensure a control overlaps another one.

Check the PictureContainer class in this post for an approach that works at design time.

Community
  • 1
  • 1
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
0

Calling the Invalidate method does not force a synchronous paint; to force a synchronous paint, call the Update method after calling the Invalidate method. When this method is called with no parameters, the entire client area is added to the update region.

From MSDN Control.Invalidate() method.

Sinatr
  • 20,892
  • 15
  • 90
  • 319
melya
  • 578
  • 5
  • 24
  • Thanks, I thought I had a clue here, because when I added Update() I got an InvalidOperationException because the event was not generated in the thread that created the control. I tried the instructions about using [thread safe calls](https://msdn.microsoft.com/en-us/library/ms171728(v=vs.110).aspx) and implemented a delegate call using this.Invoke, but still no joy. No combination of Invalidate/Refresh/Update actually generates the call to OnPaint. – Aharon Manne Dec 15 '15 at 13:15
  • Did you try [Control.Invoke](https://msdn.microsoft.com/en-us/library/zyzhdc6b(v=vs.110).aspx) Method? You can call a `delegate` in `Control` thread from you background thread. In delegate you can call `Update()`. – melya Dec 15 '15 at 13:31