David L. Hansen
asked on
Paint events - determine when a paint event has finished.
I'd like to know if one can determine programmatically when a paint event has just completed.
Easiest way that comes to mind is the following:
Inherit a class, say TextBox
then create an After_Paint Event
Override the OnPaint event, raising After_Paint when done.
eg:
Class MyTextBox : TextBox
{
Public Event After_Paint
Protected void Overrides OnPaint(e as System.EventArgs)
{
base.OnPaint(e);
RaiseEvent After_Paint;
}
}
NOTE: Code was done by hand, may have syntax error but displays general idea.
Inherit a class, say TextBox
then create an After_Paint Event
Override the OnPaint event, raising After_Paint when done.
eg:
Class MyTextBox : TextBox
{
Public Event After_Paint
Protected void Overrides OnPaint(e as System.EventArgs)
{
base.OnPaint(e);
RaiseEvent After_Paint;
}
}
NOTE: Code was done by hand, may have syntax error but displays general idea.
ASKER
TwynFeyr: It seems that OnPaint just allows me to force the paint event to fire. But thanks for the suggestion.
Here is some context: I have a datagridview and that flicker bug is becoming a problem (for those of you not aware of the bug...a datagridview placed on a form with a background image will often cause horrible flicker of the screen when the datagridview is painting itself - there is a lot of documentation of this if you search for it - affecting VS 2005 and older). I have minimized this issue but it is still a problem. I want to just tell the grid's paint event to set the form's background to nothing (done that), then - when the grid's paint event is finished, reset the form's backgroundimage to what it was (here in is my problem).
Here is some context: I have a datagridview and that flicker bug is becoming a problem (for those of you not aware of the bug...a datagridview placed on a form with a background image will often cause horrible flicker of the screen when the datagridview is painting itself - there is a lot of documentation of this if you search for it - affecting VS 2005 and older). I have minimized this issue but it is still a problem. I want to just tell the grid's paint event to set the form's background to nothing (done that), then - when the grid's paint event is finished, reset the form's backgroundimage to what it was (here in is my problem).
Hi again,
overide onpaint is fired everytime a paint event is raised. If you put it directly in a winform it'll fire for the form's events. If you do as ger325 suggested it'll fire when paint events are raised for the control class you have inherited (which in this case after the question had further context added) is a better suggestion.
however, I'd be wary as alot of paint events can be raised in a very short amount of time depending on the circumstances. resizing a form usually forces all the controls to repaint if they are docked or anchored to resize on form resize. Also when the form becomes smaller and then bigger than the controls on the form there is alot of repainting. you may end up replacing one flicker, for a different kind.
i look forward to hearing about your progress.
Cheers!
TwynFeyr
overide onpaint is fired everytime a paint event is raised. If you put it directly in a winform it'll fire for the form's events. If you do as ger325 suggested it'll fire when paint events are raised for the control class you have inherited (which in this case after the question had further context added) is a better suggestion.
however, I'd be wary as alot of paint events can be raised in a very short amount of time depending on the circumstances. resizing a form usually forces all the controls to repaint if they are docked or anchored to resize on form resize. Also when the form becomes smaller and then bigger than the controls on the form there is alot of repainting. you may end up replacing one flicker, for a different kind.
i look forward to hearing about your progress.
Cheers!
TwynFeyr
ASKER
Yes, that really is the root of the problem. I need to know when the grid is beginning to paint itself so I can disable the background, then have an event fire when it is completed with all of its interior paint events. This may not be possible, but that is what I'm after.
Setting the background = nothing for each descrete paint event is not a big deal. There is no flicker issue there. So, if all I can get is the "FinishedPaintingTheWholeG rid" event, I'm in good shape.
Setting the background = nothing for each descrete paint event is not a big deal. There is no flicker issue there. So, if all I can get is the "FinishedPaintingTheWholeG
I think the grid paint event may be fired again when you change the background color.
Have you tried putting the grid into a panel of same size as grid? This may not solve the problem but worth the try.
Have you tried putting the grid into a panel of same size as grid? This may not solve the problem but worth the try.
Inherit the datagrid:
implement this for your paint:
Boolean _painting = false;
Protected void Overrides OnPaint(e as System.EventArgs)
{
if (!_painting)
{
_painting = true;
//set background image to nothing
base.OnPaint(e);
//set background image back.
_painting = false;
}
}
and also turn on double buffering: (modified from http://bitmatic.com/c/fixing-a-slow-scrolling-datagridview)
new()
{
Type dgvType = this.GetType();
PropertyInfo pi = dgvType.GetProperty("Doubl eBuffered" ,
BindingFlags.Instance | BindingFlags.NonPublic);
pi.SetValue(this, true, null);
}
implement this for your paint:
Boolean _painting = false;
Protected void Overrides OnPaint(e as System.EventArgs)
{
if (!_painting)
{
_painting = true;
//set background image to nothing
base.OnPaint(e);
//set background image back.
_painting = false;
}
}
and also turn on double buffering: (modified from http://bitmatic.com/c/fixing-a-slow-scrolling-datagridview)
new()
{
Type dgvType = this.GetType();
PropertyInfo pi = dgvType.GetProperty("Doubl
BindingFlags.Instance | BindingFlags.NonPublic);
pi.SetValue(this, true, null);
}
ASKER
CodeCruiser,
The panel didn't help. Too bad, it would have been the easiest solution.
ged325,
I really like your idea and am trying to implement it. I'm in VB, so I've converted the code. Two things: First, the following code causes constant flicker when the form loads...the flicker never stops (it paints the background as nothing then the image, then nothing, then the image, etc., etc. very very fast). Secondly, I don't see how I can generically set the background of the form to nothing within the custom datagridview class. I certainly can force it through "my.Forms.mySpecificFrom.B ackgroundI mage = Nothing" but then I can't reuse the code without rewriting that line of code each time I drop a grid on a form. Is there a way I can generically point to the parent form?
Here is the code:
To make it really reuasable I think I'll put in a test to see if a background image exists.
The panel didn't help. Too bad, it would have been the easiest solution.
ged325,
I really like your idea and am trying to implement it. I'm in VB, so I've converted the code. Two things: First, the following code causes constant flicker when the form loads...the flicker never stops (it paints the background as nothing then the image, then nothing, then the image, etc., etc. very very fast). Secondly, I don't see how I can generically set the background of the form to nothing within the custom datagridview class. I certainly can force it through "my.Forms.mySpecificFrom.B
Here is the code:
Public NotInheritable Class DatagridViewPlus
Inherits DataGridView
Dim _painting As Boolean = False
Private Sub New()
Dim dgvType As Type = Me.[GetType]()
Dim pi As PropertyInfo = dgvType.GetProperty("DoubleBuffered", BindingFlags.Instance Or BindingFlags.NonPublic)
pi.SetValue(Me, True, Nothing)
End Sub
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
_painting = True
My.Forms.frmMain.BackgroundImage = Nothing '<******** Too specific
MyBase.OnPaint(e)
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(frmBuyer))
My.Forms.frmMain.BackgroundImage = CType(resources.GetObject("$this.BackgroundImage"), System.Drawing.Image)
_painting = False
End Sub
End Class
To make it really reuasable I think I'll put in a test to see if a background image exists.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
There is no "GetForm" method for DatagridViews. But there is a "Parent" property which I've not tried.
Also, getting the image is not a problem. The "Dim resources ..." line and the "...$this.BackgroundImage" line work wonderfully. I've tested those. I think perhaps the sequencing is funny...not sure, but there is definitely an infinite loop going on.
Also, getting the image is not a problem. The "Dim resources ..." line and the "...$this.BackgroundImage"
the infinite loop comes from setting the background to null. Which is intern triggering the paint event again . . . Hence the mutex like options.
Once it's in the on_paint, it needs to skip it for all other calls.
Regarding the .Parent . . . I've had issues with that where it was nothing even after being loaded.
You may want to create another property and set the property from the control.
As for the resources line . . . that may work for this app but was trying to make it as generic as possible. If you're okay with it though that's what counts.
Once it's in the on_paint, it needs to skip it for all other calls.
Regarding the .Parent . . . I've had issues with that where it was nothing even after being loaded.
You may want to create another property and set the property from the control.
As for the resources line . . . that may work for this app but was trying to make it as generic as possible. If you're okay with it though that's what counts.
ASKER
Cruiser, Ged, and Twyn,
Truly sorry for the long delay guys (and through the E-E-Derby too)! I've been trying to duplicate the flicker, in a test project, and fix it with the custom grid. The problem is, I've been getting inconsistent results. Without determining all the variables contributing to the problem, I'm reluctant to close this post (and give out an incomplete answer). I'll continue testing with this and won't neglect this post; it may take some time however (as I do have a band-aid fix, which my boss is happy with). I will definitely work on it as I have time to do so -- I really do want to pin this down.
Truly sorry for the long delay guys (and through the E-E-Derby too)! I've been trying to duplicate the flicker, in a test project, and fix it with the custom grid. The problem is, I've been getting inconsistent results. Without determining all the variables contributing to the problem, I'm reluctant to close this post (and give out an incomplete answer). I'll continue testing with this and won't neglect this post; it may take some time however (as I do have a band-aid fix, which my boss is happy with). I will definitely work on it as I have time to do so -- I really do want to pin this down.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I'll definitely give your idea a shot and let you know the results :)
>and through the E-E-Derby too
Curious on the use of Derby word as its the city I live in.
Curious on the use of Derby word as its the city I live in.
ASKER
I was just referring to the Grand-Prix competition Experts-Exchange was having at the time.
Oh ok.
ASKER
The Derby in England?
Yes
ASKER
I'm working on this today. I hope I can finish this off and that it will work...thanks for your help and patients.
ASKER
I need to just tie this up. I believe your approach will work TwynFyer; I'm going to award the points without actually testing because I just don't know when I'll be able to. I was basically told me to forget the "Pretty backgrounds" and finish the job. Too bad really.
ASKER
Thank you very very much.
Open in new window
base.OnPaint(e) does it's thing and then you do your afterwardshere's a link to MSDN
Control.OnPaint method