Odd GDI bug - Full and complete example enclosed!

S

Simon Tamman

I was trying to double buffer a control while drawing on CE devices. The code
below is compiled under the compact framework but you can also run it on the
desktop and it produces the same problem.

The basic problem is that my controls don't seem to correctly process an
invalidate call after a window is dropped on top on them, mainly the "cheat"
windows such as a combobox drop down or a loading symbol or volume control
(which you get in CE)

Example below, please let me know if you have ideas, the issue seems to be
the override Paint in the DoubleBufferedControl. What is wrong with this
code? It looks good to me.

1.
using System;
2.
using System.Collections.Generic;
3.
using System.Windows.Forms;
4.
using System.Text;
5.
using System.Drawing;
6.

7.

8.
namespace DeviceApplication9
9.
{
10.
static class Program
11.
{
12.
/// <summary>
13.
/// The main entry point for the application.
14.
/// </summary>
15.
[MTAThread]
16.
static void Main()
17.
{
18.
Application.Run(new Form1());
19.
}
20.

21.

22.

23.

24.
}
25.

26.
class CustomControl : DoubleBufferedControl
27.
{
28.

29.
protected override void DoPaint(PaintEventArgs e)
30.
{
31.
using (SolidBrush back = new
SolidBrush(Color.Red))
32.
{
33.
e.Graphics.FillRectangle(back,
e.ClipRectangle);
34.
}
35.
using (SolidBrush fore = new
SolidBrush(Color.White))
36.
{
37.
e.Graphics.DrawString(Text, Font,
fore, e.ClipRectangle);
38.
}
39.
}
40.

41.
}
42.

43.
class CustomLabel : Label
44.
{
45.

46.
protected override void
OnPaintBackground(PaintEventArgs pevent)
47.
{
48.
// do nothing, prevent flicker
49.
}
50.

51.
protected override void OnPaint(PaintEventArgs e)
52.
{
53.
using (SolidBrush back = new
SolidBrush(Color.Red))
54.
{
55.
e.Graphics.FillRectangle(back,
e.ClipRectangle);
56.
}
57.
using (SolidBrush fore = new
SolidBrush(Color.White))
58.
{
59.
e.Graphics.DrawString(Text, Font,
fore, e.ClipRectangle);
60.
}
61.
}
62.
}
63.

64.
/// <summary>
65.
/// <para>Provides double buffering functionality from any
control that inherits from this one.</para>
66.
/// <para>Override the DoPaint method to add your custom paint
code</para>
67.
/// </summary>
68.
public class DoubleBufferedControl : Control
69.
{
70.
#region Fields
71.

72.
private Graphics m_BackGraphics;
73.
private Bitmap m_BackBuffer;
74.

75.
#endregion
76.

77.
#region Ctor
78.

79.
/// <summary>
80.
/// Constructor
81.
/// </summary>
82.
protected DoubleBufferedControl()
83.
{
84.
}
85.

86.
#endregion
87.

88.
#region Private Impl
89.

90.
/// <summary>
91.
/// <para>Overrides the paint background event and
does nothing.</para>
92.
/// <para>If this isn't overidden then double
buffering wont work</para>
93.
/// </summary>
94.
/// <param name="e"></param>
95.
protected override void
OnPaintBackground(PaintEventArgs e)
96.
{
97.
// do nothing
98.
}
99.

100.
/// <summary>
101.
/// Overrides the paint event and performs double
buffering
102.
/// </summary>
103.
/// <param name="e"></param>
104.
protected override void OnPaint(PaintEventArgs e)
105.
{
106.
if (e.ClipRectangle.Width > 0 &&
e.ClipRectangle.Height > 0)
107.
{
108.
using (m_BackBuffer = new
Bitmap(e.ClipRectangle.Width, e.ClipRectangle.Height))
109.
{
110.
using (m_BackGraphics =
Graphics.FromImage(m_BackBuffer))
111.
{
112.
DoPaint(new
PaintEventArgs(m_BackGraphics, e.ClipRectangle));
113.
}
114.

e.Graphics.DrawImage(m_BackBuffer, 0, 0);
115.
}
116.
}
117.
}
118.

119.
/// <summary>
120.
/// Performs the paint event in the subclass
121.
/// </summary>
122.
/// <param name="e"></param>
123.
protected virtual void DoPaint(PaintEventArgs e)
124.
{
125.
// do nothing, for overrides only
126.
}
127.

128.
/// <summary>
129.
/// Overrides the dispose method to dispose the
backgraphics and
130.
/// back buffer if they have not yet been disposed.
131.
/// </summary>
132.
/// <param name="disposing"></param>
133.
protected override void Dispose(bool disposing)
134.
{
135.
base.Dispose(disposing);
136.
if (disposing)
137.
{
138.
if (m_BackGraphics != null)
139.
{
140.
m_BackGraphics.Dispose();
141.
m_BackGraphics = null;
142.
}
143.
if (m_BackBuffer != null)
144.
{
145.
m_BackBuffer.Dispose();
146.
m_BackBuffer = null;
147.
}
148.
}
149.
}
150.

151.
#endregion
152.
}
153.

154.
public partial class Form1 : Form
155.
{
156.
public Form1()
157.
{
158.
InitializeComponent();
159.
CustomControl control = new CustomControl();
160.
control.Text =
"hthttehstehrjgsjgsfkgdgjmrknvrgnrkgrvnsgrkrgdsjgrdhjn";
161.
control.Bounds = new Rectangle(100, 100, 100,
50);
162.
CustomLabel label = new CustomLabel();
163.
label.Text =
"hthttehstehrjgsjgsfkgdgjmrknvrgnrkgrvnsgrkrgdsjgrdhjn";
164.
label.Bounds = new Rectangle(100, 200, 100, 50);
165.
Controls.Add(control);
166.
Controls.Add(label);
167.
}
168.

169.
private void button1_Click(object sender, EventArgs e)
170.
{
171.
Close();
172.
}
173.
}
174.

175.
partial class Form1
176.
{
177.
/// <summary>
178.
/// Required designer variable.
179.
/// </summary>
180.
private System.ComponentModel.IContainer components =
null;
181.
private System.Windows.Forms.MainMenu mainMenu1;
182.

183.
/// <summary>
184.
/// Clean up any resources being used.
185.
/// </summary>
186.
/// <param name="disposing">true if managed resources
should be disposed; otherwise, false.</param>
187.
protected override void Dispose(bool disposing)
188.
{
189.
if (disposing && (components != null))
190.
{
191.
components.Dispose();
192.
}
193.
base.Dispose(disposing);
194.
}
195.

196.
#region Windows Form Designer generated code
197.

198.
/// <summary>
199.
/// Required method for Designer support - do not modify
200.
/// the contents of this method with the code editor.
201.
/// </summary>
202.
private void InitializeComponent()
203.
{
204.
this.mainMenu1 = new
System.Windows.Forms.MainMenu();
205.
this.button1 = new
System.Windows.Forms.Button();
206.
this.SuspendLayout();
207.
//
208.
// button1
209.
//
210.
this.button1.Location = new
System.Drawing.Point(77, 233);
211.
this.button1.Name = "button1";
212.
this.button1.Size = new
System.Drawing.Size(72, 20);
213.
this.button1.TabIndex = 0;
214.
this.button1.Text = "Close";
215.
this.button1.Click += new
System.EventHandler(this.button1_Click);
216.
//
217.
// Form1
218.
//
219.
this.AutoScaleDimensions = new
System.Drawing.SizeF(96F, 96F);
220.
this.AutoScaleMode =
System.Windows.Forms.AutoScaleMode.Dpi;
221.
this.AutoScroll = true;
222.
this.ClientSize = new System.Drawing.Size(240,
268);
223.
this.Controls.Add(this.button1);
224.
this.Menu = this.mainMenu1;
225.
this.Name = "Form1";
226.
this.Text = "Form1";
227.
this.ResumeLayout(false);
228.

229.
}
230.

231.
#endregion
232.

233.
private System.Windows.Forms.Button button1;
234.
}
235.
}
 
S

Simon Tamman

Bah, sorry its been through pastebin and has been polluted with line numbers.
I can repost the original without the line numbers in a few hous when I get
home.....

Simon Tamman said:
I was trying to double buffer a control while drawing on CE devices. The code
below is compiled under the compact framework but you can also run it on the
desktop and it produces the same problem.

The basic problem is that my controls don't seem to correctly process an
invalidate call after a window is dropped on top on them, mainly the "cheat"
windows such as a combobox drop down or a loading symbol or volume control
(which you get in CE)

Example below, please let me know if you have ideas, the issue seems to be
the override Paint in the DoubleBufferedControl. What is wrong with this
code? It looks good to me.

1.
using System;
2.
using System.Collections.Generic;
3.
using System.Windows.Forms;
4.
using System.Text;
5.
using System.Drawing;
6.

7.

8.
namespace DeviceApplication9
9.
{
10.
static class Program
11.
{
12.
/// <summary>
13.
/// The main entry point for the application.
14.
/// </summary>
15.
[MTAThread]
16.
static void Main()
17.
{
18.
Application.Run(new Form1());
19.
}
20.

21.

22.

23.

24.
}
25.

26.
class CustomControl : DoubleBufferedControl
27.
{
28.

29.
protected override void DoPaint(PaintEventArgs e)
30.
{
31.
using (SolidBrush back = new
SolidBrush(Color.Red))
32.
{
33.
e.Graphics.FillRectangle(back,
e.ClipRectangle);
34.
}
35.
using (SolidBrush fore = new
SolidBrush(Color.White))
36.
{
37.
e.Graphics.DrawString(Text, Font,
fore, e.ClipRectangle);
38.
}
39.
}
40.

41.
}
42.

43.
class CustomLabel : Label
44.
{
45.

46.
protected override void
OnPaintBackground(PaintEventArgs pevent)
47.
{
48.
// do nothing, prevent flicker
49.
}
50.

51.
protected override void OnPaint(PaintEventArgs e)
52.
{
53.
using (SolidBrush back = new
SolidBrush(Color.Red))
54.
{
55.
e.Graphics.FillRectangle(back,
e.ClipRectangle);
56.
}
57.
using (SolidBrush fore = new
SolidBrush(Color.White))
58.
{
59.
e.Graphics.DrawString(Text, Font,
fore, e.ClipRectangle);
60.
}
61.
}
62.
}
63.

64.
/// <summary>
65.
/// <para>Provides double buffering functionality from any
control that inherits from this one.</para>
66.
/// <para>Override the DoPaint method to add your custom paint
code</para>
67.
/// </summary>
68.
public class DoubleBufferedControl : Control
69.
{
70.
#region Fields
71.

72.
private Graphics m_BackGraphics;
73.
private Bitmap m_BackBuffer;
74.

75.
#endregion
76.

77.
#region Ctor
78.

79.
/// <summary>
80.
/// Constructor
81.
/// </summary>
82.
protected DoubleBufferedControl()
83.
{
84.
}
85.

86.
#endregion
87.

88.
#region Private Impl
89.

90.
/// <summary>
91.
/// <para>Overrides the paint background event and
does nothing.</para>
92.
/// <para>If this isn't overidden then double
buffering wont work</para>
93.
/// </summary>
94.
/// <param name="e"></param>
95.
protected override void
OnPaintBackground(PaintEventArgs e)
96.
{
97.
// do nothing
98.
}
99.

100.
/// <summary>
101.
/// Overrides the paint event and performs double
buffering
102.
/// </summary>
103.
/// <param name="e"></param>
104.
protected override void OnPaint(PaintEventArgs e)
105.
{
106.
if (e.ClipRectangle.Width > 0 &&
e.ClipRectangle.Height > 0)
107.
{
108.
using (m_BackBuffer = new
Bitmap(e.ClipRectangle.Width, e.ClipRectangle.Height))
109.
{
110.
using (m_BackGraphics =
Graphics.FromImage(m_BackBuffer))
111.
{
112.
DoPaint(new
PaintEventArgs(m_BackGraphics, e.ClipRectangle));
113.
}
114.

e.Graphics.DrawImage(m_BackBuffer, 0, 0);
115.
}
116.
}
117.
}
118.

119.
/// <summary>
120.
/// Performs the paint event in the subclass
121.
/// </summary>
122.
/// <param name="e"></param>
123.
protected virtual void DoPaint(PaintEventArgs e)
124.
{
125.
// do nothing, for overrides only
126.
}
127.

128.
/// <summary>
129.
/// Overrides the dispose method to dispose the
backgraphics and
130.
/// back buffer if they have not yet been disposed.
131.
/// </summary>
132.
/// <param name="disposing"></param>
133.
protected override void Dispose(bool disposing)
 
S

Simon Tamman

You can see it with proper formatting here though:

http://www.pastebin.ca/1037371

Simon Tamman said:
Bah, sorry its been through pastebin and has been polluted with line numbers.
I can repost the original without the line numbers in a few hous when I get
home.....

Simon Tamman said:
I was trying to double buffer a control while drawing on CE devices. The code
below is compiled under the compact framework but you can also run it on the
desktop and it produces the same problem.

The basic problem is that my controls don't seem to correctly process an
invalidate call after a window is dropped on top on them, mainly the "cheat"
windows such as a combobox drop down or a loading symbol or volume control
(which you get in CE)

Example below, please let me know if you have ideas, the issue seems to be
the override Paint in the DoubleBufferedControl. What is wrong with this
code? It looks good to me.

1.
using System;
2.
using System.Collections.Generic;
3.
using System.Windows.Forms;
4.
using System.Text;
5.
using System.Drawing;
6.

7.

8.
namespace DeviceApplication9
9.
{
10.
static class Program
11.
{
12.
/// <summary>
13.
/// The main entry point for the application.
14.
/// </summary>
15.
[MTAThread]
16.
static void Main()
17.
{
18.
Application.Run(new Form1());
19.
}
20.

21.

22.

23.

24.
}
25.

26.
class CustomControl : DoubleBufferedControl
27.
{
28.

29.
protected override void DoPaint(PaintEventArgs e)
30.
{
31.
using (SolidBrush back = new
SolidBrush(Color.Red))
32.
{
33.
e.Graphics.FillRectangle(back,
e.ClipRectangle);
34.
}
35.
using (SolidBrush fore = new
SolidBrush(Color.White))
36.
{
37.
e.Graphics.DrawString(Text, Font,
fore, e.ClipRectangle);
38.
}
39.
}
40.

41.
}
42.

43.
class CustomLabel : Label
44.
{
45.

46.
protected override void
OnPaintBackground(PaintEventArgs pevent)
47.
{
48.
// do nothing, prevent flicker
49.
}
50.

51.
protected override void OnPaint(PaintEventArgs e)
52.
{
53.
using (SolidBrush back = new
SolidBrush(Color.Red))
54.
{
55.
e.Graphics.FillRectangle(back,
e.ClipRectangle);
56.
}
57.
using (SolidBrush fore = new
SolidBrush(Color.White))
58.
{
59.
e.Graphics.DrawString(Text, Font,
fore, e.ClipRectangle);
60.
}
61.
}
62.
}
63.

64.
/// <summary>
65.
/// <para>Provides double buffering functionality from any
control that inherits from this one.</para>
66.
/// <para>Override the DoPaint method to add your custom paint
code</para>
67.
/// </summary>
68.
public class DoubleBufferedControl : Control
69.
{
70.
#region Fields
71.

72.
private Graphics m_BackGraphics;
73.
private Bitmap m_BackBuffer;
74.

75.
#endregion
76.

77.
#region Ctor
78.

79.
/// <summary>
80.
/// Constructor
81.
/// </summary>
82.
protected DoubleBufferedControl()
83.
{
84.
}
85.

86.
#endregion
87.

88.
#region Private Impl
89.

90.
/// <summary>
91.
/// <para>Overrides the paint background event and
does nothing.</para>
92.
/// <para>If this isn't overidden then double
buffering wont work</para>
93.
/// </summary>
94.
/// <param name="e"></param>
95.
protected override void
OnPaintBackground(PaintEventArgs e)
96.
{
97.
// do nothing
98.
}
99.

100.
/// <summary>
101.
/// Overrides the paint event and performs double
buffering
102.
/// </summary>
103.
/// <param name="e"></param>
104.
protected override void OnPaint(PaintEventArgs e)
105.
{
106.
if (e.ClipRectangle.Width > 0 &&
e.ClipRectangle.Height > 0)
107.
{
108.
using (m_BackBuffer = new
Bitmap(e.ClipRectangle.Width, e.ClipRectangle.Height))
109.
{
110.
using (m_BackGraphics =
Graphics.FromImage(m_BackBuffer))
111.
{
112.
DoPaint(new
PaintEventArgs(m_BackGraphics, e.ClipRectangle));
113.
}
114.

e.Graphics.DrawImage(m_BackBuffer, 0, 0);
115.
}
116.
}
117.
}
118.

119.
/// <summary>
120.
/// Performs the paint event in the subclass
121.
/// </summary>
122.
/// <param name="e"></param>
123.
protected virtual void DoPaint(PaintEventArgs e)
124.
{
125.
// do nothing, for overrides only
126.
}
127.

128.
/// <summary>
129.
/// Overrides the dispose method to dispose the
backgraphics and
130.
/// back buffer if they have not yet been disposed.
 
G

gerry

man that pastebin is terrible - how do that many scripting errors make it
onto a live site ?



Simon Tamman said:
You can see it with proper formatting here though:

http://www.pastebin.ca/1037371

Simon Tamman said:
Bah, sorry its been through pastebin and has been polluted with line
numbers.
I can repost the original without the line numbers in a few hous when I
get
home.....

Simon Tamman said:
I was trying to double buffer a control while drawing on CE devices.
The code
below is compiled under the compact framework but you can also run it
on the
desktop and it produces the same problem.

The basic problem is that my controls don't seem to correctly process
an
invalidate call after a window is dropped on top on them, mainly the
"cheat"
windows such as a combobox drop down or a loading symbol or volume
control
(which you get in CE)

Example below, please let me know if you have ideas, the issue seems to
be
the override Paint in the DoubleBufferedControl. What is wrong with
this
code? It looks good to me.

1.
using System;
2.
using System.Collections.Generic;
3.
using System.Windows.Forms;
4.
using System.Text;
5.
using System.Drawing;
6.

7.

8.
namespace DeviceApplication9
9.
{
10.
static class Program
11.
{
12.
/// <summary>
13.
/// The main entry point for the application.
14.
/// </summary>
15.
[MTAThread]
16.
static void Main()
17.
{
18.
Application.Run(new Form1());
19.
}
20.

21.

22.

23.

24.
}
25.

26.
class CustomControl : DoubleBufferedControl
27.
{
28.

29.
protected override void DoPaint(PaintEventArgs e)
30.
{
31.
using (SolidBrush back = new
SolidBrush(Color.Red))
32.
{
33.
e.Graphics.FillRectangle(back,
e.ClipRectangle);
34.
}
35.
using (SolidBrush fore = new
SolidBrush(Color.White))
36.
{
37.
e.Graphics.DrawString(Text, Font,
fore, e.ClipRectangle);
38.
}
39.
}
40.

41.
}
42.

43.
class CustomLabel : Label
44.
{
45.

46.
protected override void
OnPaintBackground(PaintEventArgs pevent)
47.
{
48.
// do nothing, prevent flicker
49.
}
50.

51.
protected override void OnPaint(PaintEventArgs e)
52.
{
53.
using (SolidBrush back = new
SolidBrush(Color.Red))
54.
{
55.
e.Graphics.FillRectangle(back,
e.ClipRectangle);
56.
}
57.
using (SolidBrush fore = new
SolidBrush(Color.White))
58.
{
59.
e.Graphics.DrawString(Text, Font,
fore, e.ClipRectangle);
60.
}
61.
}
62.
}
63.

64.
/// <summary>
65.
/// <para>Provides double buffering functionality from
any
control that inherits from this one.</para>
66.
/// <para>Override the DoPaint method to add your custom
paint
code</para>
67.
/// </summary>
68.
public class DoubleBufferedControl : Control
69.
{
70.
#region Fields
71.

72.
private Graphics m_BackGraphics;
73.
private Bitmap m_BackBuffer;
74.

75.
#endregion
76.

77.
#region Ctor
78.

79.
/// <summary>
80.
/// Constructor
81.
/// </summary>
82.
protected DoubleBufferedControl()
83.
{
84.
}
85.

86.
#endregion
87.

88.
#region Private Impl
89.

90.
/// <summary>
91.
/// <para>Overrides the paint background event
and
does nothing.</para>
92.
/// <para>If this isn't overidden then double
buffering wont work</para>
93.
/// </summary>
94.
/// <param name="e"></param>
95.
protected override void
OnPaintBackground(PaintEventArgs e)
96.
{
97.
// do nothing
98.
}
99.

100.
/// <summary>
101.
/// Overrides the paint event and performs double
buffering
102.
/// </summary>
103.
/// <param name="e"></param>
104.
protected override void OnPaint(PaintEventArgs e)
105.
{
106.
if (e.ClipRectangle.Width > 0 &&
e.ClipRectangle.Height > 0)
107.
{
108.
using (m_BackBuffer = new
Bitmap(e.ClipRectangle.Width, e.ClipRectangle.Height))
109.
{
110.
using (m_BackGraphics =
Graphics.FromImage(m_BackBuffer))
111.
{
112.
DoPaint(new
PaintEventArgs(m_BackGraphics, e.ClipRectangle));
113.
}
114.

e.Graphics.DrawImage(m_BackBuffer, 0, 0);
115.
}
116.
}
117.
}
118.

119.
/// <summary>
120.
/// Performs the paint event in the subclass
121.
/// </summary>
122.
/// <param name="e"></param>
123.
protected virtual void DoPaint(PaintEventArgs e)
124.
{
125.
// do nothing, for overrides only
126.
}
127.

128.
/// <summary>
129.
/// Overrides the dispose method to dispose the
backgraphics and
130.
/// back buffer if they have not yet been
disposed.
 
S

Simon Tamman

Yay! Converting everything to ClientRectangle seems to do the trick!
Thank you very much!

Peter Duniho said:
First suggestion: deciding that something is a bug in .NET or especially
in GDI should be a VERY last resort. It's almost never actually true, and
making that assumption makes it that much harder for you to notice the
flaws in your own code.

That wasn't my intention, perhaps I should have labeled it differently, I
was trying to suggest I had a bug and it was to do with the GDI. I certainly
believe that the problem lies within my own code which is why I posted a full
example showing that the issue was with the routine in my "double buffered
control".
Second suggestion: when describing a problem, _describe_ the problem.
Don't write "don't seem to correctly process an invalidate call". Explain
in detail what actually happens and why that's different from what you
expected. As things stand now, even if I were to run the code, I would
have no idea what of all the various problems that might occur is or are
the ones troubling you presently.

Apologies again, I listed this because a manual Invalidate call to the
control fixes the issue so I assumed it was to do with Invalidate. My idiocy
at play there.
Now, as far as the code you posted goes, I see a number of implementation
problems. A few things of particular concern are:

* Why are you making the back-buffer Bitmap and Graphics instance
member variables, when you always dispose them when you're done? Why
aren't these just locals?

Fair point, I was considering only creating them only on resize so I made
them member variables and then didn't get round to changing the code.
* Why are you using the ClipRectangle to create the backbuffer, but
then drawing to the origin of your ClientRectangle? And why are you using
the same ClipRectangle in your new PaintEventArgs, when you've completely
changed the effective coordinate system by creating a new back-buffer
Bitmap into which the DoPaint() method will draw?

I guess I should read-up on the docs on e.ClipRectangle. I always figured it
was telling you where to draw and using ClientRectangle was kinda cheating. I
should probably RTFM.
* Why don't you initialize the back-buffer Bitmap? Do you really want
your control drawn with the default background (black) a brand-new Bitmap
instance gives you?

Yea, the sub class renders the whole thing, so i'm not concerned about
initialising the bitmap.
* Why are you going to all this trouble at all? Why not just set the
DoubleBuffered property to true, and let .NET do all the work?

It's not supported in Compact Framework 2.00. Nor is SetStyles()
Finally: note that making a given _control_ double-buffered isn't
necessarily going to eliminate flicker. If the parent form isn't
double-buffered and if the parent form redraws its own background without
excluding the child controls, then the controls will flicker in any case.

It does result in a noticeable rendering improvement on CE devices.
Perhaps I should also override the form's OnPaint to do the same thing to
further improve things?
It's also suspicious that you explicitly override and ignore the
OnPaintBackground() method, but don't actually have any code that
explicitly paints the background. This might be okay as long as you
always paint the entire control in OnPaint(). But you don't.

But I do! Don't I?
If I didn't override OnPaintBackground and leave it empty then the double
buffering didn't work.
Also note that you don't need a custom Label sub-class to prevent flicker
from your Label controls. Just make the containing Form double-buffered
(again, simply by setting the DoubleBuffered property to true). Of
course, it begs the question why you are bothering to override the Label
control at all, given that you don't use any of the existing
implementation's drawing code. Why not just make your own custom label in
that case?

The label override was just to test the difference between Control and
Label. I first thought the issue might be this, later I noticed that it was
the DoubleBufferedControl, but I accidentally left the comparison in. The
comparison should have been Control VS Control -> DoubleBufferedControl
My advice: forget all the custom control stuff, and just set
DoubleBuffered to true in your Form sub-class's constructor. In most
cases, that accomplishes everything you'd want.

If that's not sufficient, it would probably helpful to approach the
question from the other end: don't tell us what you've written and ask why
it doesn't work; tell us what it is about the normal double-buffering that
isn't sufficient for you, and what exactly it is you hope to accomplish by
re-implementing double-buffering yourself. I think you'll get much more
useful replies to a question presented like that.

Pete

Rather than just give a hand wavey requirement that would give me lots of
Full Framework responses or cover old ground I wanted to post a full but
complete example to cut out all of the "can't do that in CF" etc etc.
I appreciate that I could have posted in a CF forum but the response time
would have been lower and I could reproduce the bug in FF so I figured it was
okay to post here instead.

Thankyou VERY much for your help though, I had difficulty working out what
that problem was.

Kind Regards

Simon Tamman
 
S

Simon Tamman

Peter Duniho said:
But I hope you at least got your money's worth. :)

I certainly did, I didn't pay anything..... wait.... do I now owe you
dollars? :)
I'm pleased I put it here as I got both a perfect and lightening fast reply.
:)
I'm not sure what "it" refers to here. Double-buffering?
Yup.

* Easier: override OnPaint(), replace the PaintEventArgs with your own
before calling base.OnPaint(), then of course do whatever rendering your
custom form code does (if any).

I shall try this, although I reckon it probably wont work.
* Harder: override WndProc(), intercept WM_PAINT messages, replacing
WM_PAINT with WM_PRINT before passing it to the base.WndProc() and then
using the results to render the window. This relies on the base class and
child controls actually handling WM_PRINT; even on non-CE versions of
Windows, I'm not sure that this is a given, and I have no idea whether it
would generally work on CE.

Yea... CF doesn't get WndProc overrides for free either, so to do this I
figure i'll have to get my hands dirty. Thank you loads for this though as it
gives me a direction to improve things in general if I want to sink the time
into it.

Thanks again!

Simon Tamman
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top