1

I have a WinForm with a docked Panel. I overrode the Panel’s Paint event. I have a line that sets up _graphics object:

private Graphics _graphics;

In the override I initialize _graphics object:

private void GridPanel_Paint(object sender, PaintEventArgs e)
{
    _graphics = e.Graphics;

    <snip>
    …
    </snip>
}

Here comes the stupid part, Can I use this _graphics object in any other event like MouseMove?

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
Randy
  • 1,137
  • 16
  • 49
  • [http://stackoverflow.com/questions/4759646/how-to-manually-get-instance-of-graphics-object-in-winforms](http://stackoverflow.com/questions/4759646/how-to-manually-get-instance-of-graphics-object-in-winforms) – Fratyx Nov 17 '15 at 14:24
  • 2
    You can (and for the sake of short code portions __should__) pass out the `e.Graphics` object __from__ the `Paint` event to helper functions. Do __not__ try to __cache__ it (and also do not use `CreateGraphics`) or else __terrible__ things will happen ! - So the answer is __NO__ you should not do that! – TaW Nov 17 '15 at 15:16

4 Answers4

3

It depends what do you mean by "use".

Graphics is disposable. After repainting, control disposes Graphics instance, that was passed into Paint event handler. From that point, disposed object is useless. But caching a reference to that instance is absolutely legal.

Dennis
  • 37,026
  • 10
  • 82
  • 150
  • In the Paint event I draw a grid in the Panel using a gray pen. In the MouseMove I want to repaint the grid square the mouse pointer is currently in with a red pen. – Randy Nov 17 '15 at 14:33
  • 3
    @Randy: you don't need to remember graphics. Instead, remember square parameters to repaint and call `Invalidate`. – Dennis Nov 17 '15 at 14:45
  • 1
    Use the MouseMove event only to identify the cell you want to change and to force a redraw of the control if that cell changed. Then in the Paint handler you add your custom drawing. – B0Andrew Nov 17 '15 at 14:46
1

You can use graphics object of your control using CreateGraphics method where you want, but when the control refreshes, your painting will disappear.

So it's better to draw what you need, in Paint event based on some logic, then each time the control refreshes, your paint logic will apply and the drawing will show on your control.

For example when you want to draw a rectangle in your MouseMove event, its enough to store the rectangle in a class member variable, and call yourControl.Invalidate(); and then use the rectangle in the Paint event handler and draw it. Invalidate makes the control redraw, so your painting logic will run.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • It's very good to post a comment about the reason of down vote and let me know what's wrong with the answer. – Reza Aghaei Nov 17 '15 at 14:38
  • Someone probebly saw `CreateGraphics` and automatically downvoted. – TaW Nov 17 '15 at 15:18
  • @TaW and how does `CreateGraphics` deserve a down vote without reading the rest of the answer. :-/ – Reza Aghaei Nov 17 '15 at 15:20
  • Didn't say it does, just think that's a plausible explanation. Some folks look for any reason to downvote.. – TaW Nov 17 '15 at 15:31
  • @TaW Thank you for your feedback. – Reza Aghaei Nov 17 '15 at 15:39
  • @TaW I think if SO shows a log for votes, we will see unreasonable votes less. – Reza Aghaei Nov 17 '15 at 15:40
  • Haha! If you want to see a real number downvotes you could suggest this on Meta. You will get -100 in under one hour, I bet.. (The reasoning is: The voting should happen uninhibited to work best. The same reason for 1 dv costing only one rep point) – TaW Nov 17 '15 at 15:43
1

Yes, you can use Graphics outside of your Paint/PaintBackground events, but you shouldn't need to, nor is it advised.

My guess is (given that you referenced MouseMove) that you want some painting to occur when particular events occur on the control; there are a couple of solutions to this:

  • Subclassing (greater control over your component, control reuse etc)
  • Registering event handlers (good for quick and dirty implementation)

Example 1 - registering event handlers

private void panel1_MouseMove(object sender, EventArgs e)
{
    // forces paint event to fire for entire control surface    
    panel1.Refresh();
}

private void panel1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.....;
}

Example 2 - subclassing

class CustomControl : Control
{
    public CustomControl()
    {
        SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer, true);
        UpdateStyles();
    }

    protected override void OnMouseMove(EventArgs e)
    {
        base.OnMouseMove(e);
        Refresh();
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        e.Graphics...;
    }
}

Notes

  1. Once OnPaint/Paint has been called, e.Graphics will be disposed, therefore, setting a global reference to that object will be useless since it will be null once your Paint event has completed.
  2. You can use CreateGraphics() if you absolutely need Graphics outside of your Paint/PaintBackground methods/events, but this isn't advised.
  3. Paint/PaintBackground fall naturally into the WinForms event/rendering pipeline, so you should ideally override these and use them appropriately.
Matthew Layton
  • 39,871
  • 52
  • 185
  • 313
1

If you want repaint panel on MouseMove event, call the Invalidate() method and do the draw logic on Paint event.

The Invalidate() method marks the panel "dirty" and the painting will be caused from winforms message-loop.

TcKs
  • 25,849
  • 11
  • 66
  • 104