7

I have OnPaint method overrided to draw an Ellipse on the screen.

    protected override void OnPaint(PaintEventArgs e)
    {
        MessageBox.Show("Paint");
        if (debugStarted)
        {
            int y = rtbLogicCode.PlaceToPoint(new Place(0, debugLine)).Y;
            if (rtbLogicCode.GetVisibleState(debugLine).ToString() == "Visible")
            {
                e.Graphics.FillEllipse(new LinearGradientBrush(new Rectangle(0, y, 15, 15), Color.LightPink, Color.Red, 45), 0, y, 15, 15);
            }
            base.OnPaint(e);
        }
    }

    private void rtbLogicCode_Scroll(object sender, ScrollEventArgs e)
    {
        this.Invalidate();
    }

The scroll event (On the Richtextbox) is handled properly but even though I am invalidating the form, it isn't calling the OnPaint function (The messagebox isn't showing).

What could be the possible cause of this?

Edit: I have forgot to mention that on my initialization function of the child form (added as a control of the main form using MDI property), I set the following styles:

 private void LogicCodeInit()
    {


            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.UserPaint, true);


    }

Edit2: I've also forgot to mention that the child form is added as a control of TabControl. The TabControl then is added as a control of the main form.

TtT23
  • 6,876
  • 34
  • 103
  • 174
  • Are you sure `this.Invalidate()` is called? What happens if you force a repainting my resizing the window? – sloth Jul 09 '12 at 06:15
  • I am sure invalidate is called (I've done a messagebox check on this too.) Also nothing happens when I resize the window. – TtT23 Jul 09 '12 at 06:17

3 Answers3

13

Call Update after Invalidate. Invalidate repaints the form only if it has focus, it's probably not getting focus since it's being added as a TabControl child.

From MSDN documentation:

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.

Jcl
  • 27,696
  • 5
  • 61
  • 92
  • Invalidate should cause the form to repaint regardless of whether it has focus, just not immediately. Your quote of the docs says nothing about focus, too. –  Jul 09 '12 at 08:10
  • The focus thing was based on experience, not on the documentation :-) – Jcl Jul 09 '12 at 08:11
  • And my experience (tested right now again for this question) shows `Invalidate` triggers `OnPaint` regardless of whether the invalidated control has focus. I'm clicking a button on form1 that invalidates form2. –  Jul 09 '12 at 08:18
  • I had a different experience on some other projects. Conditions might have varied... but anyway, Invalidating does not need to actually update the form. It just hints what should be updated. If it never gets to be updated, then the original problem might occur. Testing if `Update` does indeed update the form should at the very least not harm. – Jcl Jul 09 '12 at 08:30
  • Agreed, it's a simple test that at worst could cause slowdown or flickering, but neither should be noticeable, considering the double buffering. –  Jul 09 '12 at 08:47
1

Calling Invalidate on a control will cause invalidate some or all of it, indicating that it needs to be updated "sometime", but will not cause that update to occur immediately. Calling Update will cause any parts of a control which have been invalidated to be redrawn immediately. Calling Refresh will combine the above effects. Whenever the system is idle, it will call process updates for controls which have any invalidated regions.

The Invalidate method is useful in situations where many methods that change what should appear on a control are executed in sequence. Rather than having to redraw the control after every method that changes it, one can have the methods which change the control invalidate those parts which need redrawing. Once all the methods that might change the control have been completed, one may then use Update to redraw those parts of the control (if any) which have been invalidated. If redrawing the control would take 1/100 second, and one needs to perform fifty operations upon it, deferring and consolidating the updates may make the difference between a control which seems to update instantaneously, and one which takes a half-second.

supercat
  • 77,689
  • 9
  • 166
  • 211
0

The main reason why OnPaint might not be called is if your ControlStyle doesn't include UserPaint. I would have expected you to mention this if you did set it, so I am assuming you didn't. In that case, add a call to SetStyle in your constructor.

  • I have totally forgot to mention this but I have the following style calls added: this.SetStyle(ControlStyles.DoubleBuffer, true); this.SetStyle(ControlStyles.ResizeRedraw, true); this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); this.SetStyle(ControlStyles.UserPaint, true); – TtT23 Jul 09 '12 at 06:24
  • That *should* be enough to have `OnPaint` get called. Just to make sure, you are calling that in the constructor of the same form whose `OnPaint` you've overridden, right? And if you set a breakpoint on the entry of your `OnPaint` function, the debugger never stops? –  Jul 09 '12 at 06:32
  • BTW, the `GetStyle` part of my answer was wrong anyway, I've removed that. –  Jul 09 '12 at 06:33
  • The debugger never enters the OnPaint function when I set a breakpoint. I don't know if this matters at all, but as said above the OnPaint method is overridden on the child window, not the main window (set as MDIParent). Would paint method only be called on the main window? – TtT23 Jul 09 '12 at 06:35
  • I've used custom drawing in MDI child windows in Delphi (which I believe wraps the same winapi calls as .NET WinForms), so I wouldn't expect it to be a problem. I'll see if I can come up with a simple test project when I can. –  Jul 09 '12 at 06:37
  • I've realized something very important right now and the form I am talking about is actually added as a control of a TabControl. The tabcontrol is then added as a control of the main form. I would assume this changes a lot of thing and maybe the invalidation has to be done on the tabcontrol itself, not the form. Am I correct? – TtT23 Jul 09 '12 at 06:50
  • I've created a simple test project, and my `OnPaint` fires without a problem, and what I paint is visible. And if I add a button that calls `form2.Invalidate()`, it gets repainted when I click that button, too. Can you create a minimal project that shows the problem you're having? –  Jul 09 '12 at 08:07
  • Wait.. you're putting your form on a TabControl? Yes, that matters, that's not MDI, that's something that may look something like MDI, at best. –  Jul 09 '12 at 08:14