日期:2012-09-11  浏览次数:20584 次

鲜为人知的SetStyle方法可以让你控制重绘一个窗体的方式。
by Ken Getz
注:Ken Getz在Orlando的VSLive!上同Brian Randell一起举办了一个主题为“Build a Rich Client App with Visual Studio .NET”的研讨会。本篇技巧选自该研讨会的资料。
运用GDI+和Windows窗体,我们可以很容易地创建一个渐变色(gradient)来填充一个区域。运用.NET Framework提供的简单的方法,你可以创建linear gradients(线型渐变填充)或path gradients(路径渐变填充)。然而,真正的问题是这些复杂的背景图形是资源密集型(resource-intensive)的。最近,我正在做一个模拟的时钟演示程序,用一个渐变色来填充钟面。每一秒,当时钟重绘它的钟面来显示时钟指针的正确位置时,它也重绘了整个背景渐变色。即使在一台很快的机器上,这种方法也并不很好。我将向你介绍SetStyle方法,它可以让你指定如何、何时来重绘你的窗体。
首先,用下面的代码做试验,你可以从中得到一些着色变换的乐趣。修改一个新窗体的Paint事件使它包含该代码:
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

这里有很多代码,但它们很简单。该代码创建了一个新的GraphicsPath对象,给GraphicsPath添加一个填充了整个窗体的矩形,然后根据GraphicsPath创建一个GradientBrush对象。该代码为渐变色设置了中心点,创建了要用的渐变颜色数组,创建位置数组(颜色渐变的整个范围),创建一个新的缺省的ColorBlend对象,设置渐变色的属性,然后用渐变色填充矩形。
另外,给窗体添加一个Timer控件,激活它,将时间间隔设置为500毫秒,将下面的代码添加到Timer事件中:
Private Sub Timer1_Tick( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles Timer1.Tick  Me.Invalidate()End Sub

运行该程序,你就可以得到一个有颜色背景的漂亮的时钟了。有问题吗?是的,通常会有渐变色重绘的问题。而且画面闪动得很厉害,你不得不警惕它对视力的损伤。另外,当你尝试调整窗体大小时,你会发现,在你强迫窗体重绘前(将另一个窗体拖到该窗体上,然后移开先前的窗体。我不建议将这种方法推荐给最终用户),渐变色不会自己进行调整。
解决方法很简单:窗体的SetStyle方法可以让你设置不同的值,这些值影响窗体重绘的方式。你可以把ResizeDraw样式(style)设置为True,这样当你调整窗体的大小时,窗体就自动地重绘了。你也可以把DoubleBuffer样式设置成True,这样当每次重绘窗体的某一部分时,就不会完全重绘整个窗体了。该选项占用额外的内存,这是因为在.NET运行时,除了实际的窗体本身占用内存外,窗体图片的一个副本也必须存储在内存中,但这么做的结果是很值得的。(要运用DoubleBuffer选项,你也必须将AllPaintingInWmPaint和UserPaint样式设置成True。)在你的窗体的Load事件中添加下面的代码,你就可以完成该设置了:
Me.SetStyle(ControlStyles.ResizeRedraw, True)Me.SetStyle(ControlStyles.AllPaintingInWmPaint _    Or ControlStyles.UserPaint Or _    ControlStyles.DoubleBuffer, True)

重新运行该演示程序,你会看到你就得到了一个大小调整了的、吸引人的、填充了渐变色的数字时钟。关于这个有用的方法的更多的资料,请查看.NET Framework帮助文件中的SetStyle方法。

关于作者:
Ken Getz是MCW Technologies公司的一位高级顾问,他的时间主要用来编程、写书和培训。Ken已经编写了许多技术书籍了,包括与Paul D. Sheriff合作的ASP.NET Developer’s JumpStart。他的联系方式是keng@mcwtech.com。