Search:
Locator+ Code:
FTPOnline Channels Conferences Resources Hot Topics Partner Sites Magazines About FTP RSS 2.0 Feed
 

Repaint Your Forms With Style
The little-known SetStyle method lets you control the way a form redraws.
by Ken Getz

VSLive! Orlando, September 17, 2002

Note: Ken Getz presented the full-day workshop, "Build a Rich Client App with Visual Studio .NET," with Brian Randell at VSLive! Orlando. This tip is from that workshop's material.

It's easy to create a gradient that fills a region, using GDI+ and Windows Forms. You can create linear gradients or path gradients, using simple methods provided by the .NET Framework. The real problem, however, is that these complex background graphics are resource-intensive. Recently, I was working on an analog clock demonstration, using a gradient as the fill for the clock face. Every second, as the clock repainted its face to display the correct positioning for the clock hands, it also repainted the entire background gradient. Even on a fast machine, it wasn't pretty. I'll introduce you to the SetStyle method, which lets you specify how and when your form redraws.

To get started, try this code out for some psychedelic, tie-dyed fun. Modify a new form's Paint event so that it contains this code:

Private Sub frmMain_Paint( _
 ByVal sender As Object, _
 ByVal e As PaintEventArgs) _
 Handles MyBase.Paint

  Dim path As New GraphicsPath()
  Dim pt As New PointF()
  Dim rct As Rectangle = Me.ClientRectangle
  path.AddRectangle(rct)

  Dim pgb As New PathGradientBrush(path)
  pt = New PointF( _
   CType(Me.ClientSize.Width / 2, Single), _
   CType(Me.ClientSize.Height / 2, Single))
  pgb.CenterPoint = pt

  Dim Colors() As Color = _
   {Color.Red, Color.Orange, Color.Yellow, _
   Color.Green, _
   Color.Blue, Color.Indigo, Color.Violet}
  Dim Positions() As Single = _
   {0.0, 0.1, 0.2, 0.4, 0.6, 0.8, 1}
  Dim cb As ColorBlend = New ColorBlend()

  cb.Colors = Colors
  cb.Positions = Positions
  pgb.InterpolationColors = cb
  e.Graphics.FillRectangle(pgb, rct)

  Dim f As New StringFormat()
  f.Alignment = StringAlignment.Center
  e.Graphics.DrawString( _
   Date.Now.ToLongTimeString, _
   New Font("Tahoma", 13), Brushes.White, pt, f)
End Sub

There's a lot of code here, but it's pretty simple stuff. The code creates a new GraphicsPath object, adds a rectangle filling the whole form to the GraphicsPath, and then creates a GradientBrush object based on the GraphicsPath. The code sets up the center point for the gradient, creates an array of colors for the gradient to use, creates the array of positions (fractions of the entire radius of the gradient at which the colors change), creates a new default ColorBlend object, sets properties of the gradient, and fills the rectangle with the gradient.

In addition, add a Timer control to the form, enable it, set its interval to 500 milliseconds, and modify its Timer event so it looks like this:

Private Sub Timer1_Tick( _
 ByVal sender As System.Object, _
 ByVal e As System.EventArgs) _
 Handles Timer1.Tick

  Me.Invalidate()
End Sub

When you run the form, you get a neato clock with a colorful background. The problem? The gradient repaints. Often. And the flashing is so serious that you have to be wary of vision-induced trauma. In addition, try resizing the form—you'll find that the gradient doesn't adjust itself until you force the form to repaint (by dragging another form over it, and then removing the other form. This isn't something I'd recommend as a requirement for end users).

The solution is simple: The form's SetStyle method allows you to set various values that affect the way the form redraws. You can set the ResizeDraw style to True, so that the form automatically repaints when you resize it. You can also set the DoubleBuffer style to True, so that the form doesn't repaint the itself entirely each time it repaints any portion. This option takes up extra memory, because the .NET runtime must store a copy of the form's image in memory in addition to the memory used by the live form itself, but the results are definitely worth it. (In order to use the DoubleBuffer option, you must also set the AllPaintingInWmPaint and UserPaint styles to True.) Add this code to your form's Load event, and you're all set:

Me.SetStyle(ControlStyles.ResizeRedraw, True)
Me.SetStyle(ControlStyles.AllPaintingInWmPaint _
	Or ControlStyles.UserPaint Or _
	ControlStyles.DoubleBuffer, True)

Rerun the demo, and you'll see that you have a resizable, attractive, gradient-filled digital clock. Take a look at the SetStyle method in the .NET Framework help file for more information on this useful method.

About the Author
Ken Getz is a senior consultant with MCW Technologies and splits his time between programming, writing, and training. Ken has written many technical books, including ASP.NET Developer's JumpStart with Paul D. Sheriff. Reach Ken at keng@mcwtech.com.