自定义WinForm控件导致IDE性能下降

时间:2014-06-13 20:29:43

标签: .net vb.net winforms ide

我的控件在编译和运行后运行良好,但在设计时IDE中,一切都运行得非常笨拙。我的意思是,假设工具箱在我的UI上打开,然后关闭,它将以每秒1帧的速度移动...或者,如果我尝试移动/调整窗体上的任何控件,它将会非常移动慢。

我能做些什么来加快这个速度?

Imports System.Drawing.Imaging
Imports System.Drawing.Drawing2D
Imports System.Drawing.Text

Namespace Classes
    <ToolboxBitmap(GetType(Button))> Public Class MetroButton
        Inherits Button

        Private _color As Color = Color.FromArgb(255, 69, 129, 61)
        Private _hover As Boolean = False
        Private _mousedown As Boolean = False
        Private _forceWhite As Boolean = True

        Public Property ForceWhiteImage() As Boolean
            Get
                Return _forceWhite
            End Get
            Set(ByVal value As Boolean)
                _forceWhite = value
                Invalidate()
            End Set
        End Property
        Public Property Color() As Color
            Get
                Return _color
            End Get
            Set(ByVal value As Color)
                _color = value
                Invalidate()
            End Set
        End Property
        Protected Overrides Sub OnMouseEnter(ByVal eventargs As EventArgs)
            MyBase.OnMouseEnter(eventargs)
            _hover = True
            Invalidate()

        End Sub

        Protected Overrides Sub OnMouseLeave(ByVal eventargs As EventArgs)
            MyBase.OnMouseLeave(eventargs)
            _hover = False
            Invalidate()
        End Sub

        Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
            MyBase.OnMouseDown(e)
            If e.Button = Windows.Forms.MouseButtons.Left Then
                _mousedown = True
                Invalidate()
            End If
        End Sub

        Protected Overrides Sub OnMouseUp(ByVal e As System.Windows.Forms.MouseEventArgs)
            MyBase.OnMouseUp(e)


            _mousedown = False
            Invalidate()
        End Sub

        Private Shared Function ImageLocation(ByVal sf As StringFormat, ByVal Area As SizeF, ByVal ImageArea As SizeF) As PointF
            Dim pt As PointF

            Select Case sf.Alignment
                Case StringAlignment.Center
                    pt.X = CSng((Area.Width - ImageArea.Width) / 2)
                Case StringAlignment.Near
                    pt.X = 2
                Case StringAlignment.Far
                    pt.X = Area.Width - ImageArea.Width - 2
            End Select

            Select Case sf.LineAlignment
                Case StringAlignment.Center
                    pt.Y = CSng((Area.Height - ImageArea.Height) / 2)
                Case StringAlignment.Near
                    pt.Y = 2
                Case StringAlignment.Far
                    pt.Y = Area.Height - ImageArea.Height - 2

            End Select

            Return pt
        End Function

        Private Function GetStringFormat(ByVal ctrlalign As ContentAlignment) As StringFormat
            Dim strFormat As StringFormat = New StringFormat()
            Select Case ctrlalign
                Case ContentAlignment.MiddleCenter
                    strFormat.LineAlignment = StringAlignment.Center
                    strFormat.Alignment = StringAlignment.Center
                Case ContentAlignment.MiddleLeft
                    strFormat.LineAlignment = StringAlignment.Center
                    strFormat.Alignment = StringAlignment.Near
                Case ContentAlignment.MiddleRight
                    strFormat.LineAlignment = StringAlignment.Center
                    strFormat.Alignment = StringAlignment.Far
                Case ContentAlignment.TopCenter
                    strFormat.LineAlignment = StringAlignment.Near
                    strFormat.Alignment = StringAlignment.Center
                Case ContentAlignment.TopLeft
                    strFormat.LineAlignment = StringAlignment.Near
                    strFormat.Alignment = StringAlignment.Near
                Case ContentAlignment.TopRight
                    strFormat.LineAlignment = StringAlignment.Near
                    strFormat.Alignment = StringAlignment.Far
                Case ContentAlignment.BottomCenter
                    strFormat.LineAlignment = StringAlignment.Far
                    strFormat.Alignment = StringAlignment.Center
                Case ContentAlignment.BottomLeft
                    strFormat.LineAlignment = StringAlignment.Far
                    strFormat.Alignment = StringAlignment.Near
                Case ContentAlignment.BottomRight
                    strFormat.LineAlignment = StringAlignment.Far
                    strFormat.Alignment = StringAlignment.Far
            End Select
            strFormat.HotkeyPrefix = Drawing.Text.HotkeyPrefix.None
            Return strFormat
        End Function
        Protected Overrides Sub OnResize(ByVal e As System.EventArgs)

            'Color = Color.FromArgb(255, ClientRectangle.Width Mod 255, ClientRectangle.Width Mod 255, ClientRectangle.Width Mod 255)

            MyBase.OnResize(e)
        End Sub
        Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)

            If DesignMode Then
                e.Graphics.CompositingQuality = CompositingQuality.Default
                e.Graphics.InterpolationMode = InterpolationMode.Low
                e.Graphics.SmoothingMode = SmoothingMode.HighSpeed
                e.Graphics.TextRenderingHint = TextRenderingHint.SystemDefault

            Else
                e.Graphics.CompositingQuality = CompositingQuality.HighQuality
                e.Graphics.InterpolationMode = InterpolationMode.High
                e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
                e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit
            End If

            Using b As New SolidBrush(Color)
                e.Graphics.FillRectangle(b, ClientRectangle)
            End Using


            If _mousedown Then
                Using b As New SolidBrush(Color.FromArgb(20, 0, 0, 0))
                    e.Graphics.FillRectangle(b, ClientRectangle)
                End Using
            Else
                If _hover Then
                    Using b As New SolidBrush(Color.FromArgb(20, 255, 255, 255))
                        e.Graphics.FillRectangle(b, ClientRectangle)
                    End Using
                End If
            End If



            ' Position the imagery and text in the proper location
            If Image IsNot Nothing Then
                Dim imageSizeUse As Size

                If Not Image Is Nothing Then
                    imageSizeUse = Image.Size
                Else
                    imageSizeUse = New Size(0, 0)
                End If
                Dim textSize As SizeF = e.Graphics.MeasureString(Text, Font)
                Dim textArea As Rectangle = AdjustRect(ClientRectangle, New Padding(0))
                textArea.Width -= imageSizeUse.Width - 4

                Dim imageArea As New RectangleF(textArea.X - imageSizeUse.Width, ClientRectangle.Y, imageSizeUse.Width, imageSizeUse.Height)
                Dim imagept As PointF = ImageLocation(GetStringFormat(ImageAlign), ClientRectangle.Size, imageArea.Size)

                Select Case GetStringFormat(TextAlign).Alignment
                    Case StringAlignment.Center
                        imagept.X = ClientRectangle.X + ((ClientRectangle.Width - textSize.Width - imageSizeUse.Width) / 2) - 16
                        textArea.X = ClientRectangle.X + imageSizeUse.Width
                    Case StringAlignment.Near
                        imagept.X = ClientRectangle.X + 4
                        textArea.X = ClientRectangle.X + imageSizeUse.Width + 4
                    Case StringAlignment.Far
                        imagept.X = ClientRectangle.X + textArea.Width - textSize.Width - 12
                        textArea.X = ClientRectangle.X + imageSizeUse.Width - 8
                End Select

                imagept.Y += ClientRectangle.Y



                If _forceWhite Then
                    ' Brightness should be -1 (black) to 0 (neutral) to 1 (white)

                    Dim colorMatrixVal As Single()() = { _
                       New Single() {1, 0, 0, 0, 0}, _
                       New Single() {0, 1, 0, 0, 0}, _
                       New Single() {0, 0, 1, 0, 0}, _
                       New Single() {0, 0, 0, 1, 0}, _
                       New Single() {1, 1, 1, 0, 1}}

                    Dim colorMatrix As New ColorMatrix(colorMatrixVal)
                    Dim ia As New ImageAttributes

                    ia.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap)
                    e.Graphics.DrawImage(Image, New Rectangle(imagept.X, imagept.Y, Image.Width, Image.Height), 0, 0, Image.Width, Image.Height, GraphicsUnit.Pixel, ia)
                Else
                    e.Graphics.DrawImage(Image, imagept.X, imagept.Y, Image.Width, Image.Height)
                End If



                Using currFont As New Font("Verdana", 11)
                    e.Graphics.DrawString(Text, currFont, Brushes.White, textArea, GetStringFormat(TextAlign))
                End Using

            Else
                Using currFont As New Font("Verdana", 11)
                    Using sf As New StringFormat()
                        sf.LineAlignment = StringAlignment.Center
                        sf.Alignment = StringAlignment.Center
                        e.Graphics.DrawString(Text, currFont, Brushes.White, ClientRectangle, sf)
                    End Using
                End Using
            End If

            If Focused Then

                Dim highlightRect As Rectangle = New Rectangle(1, 1, ClientRectangle.Width - 3, ClientRectangle.Height - 3)
                Using highlightPen As Pen = New Pen(Drawing.Color.White)
                    highlightPen.Width = 1
                    highlightPen.DashStyle = Drawing2D.DashStyle.Dot
                    e.Graphics.DrawRectangle(highlightPen, highlightRect)
                End Using

            End If

            GC.Collect()
        End Sub

        Private Shared Function AdjustRect(ByVal BaseRect As RectangleF, ByVal Pad As Padding) As RectangleF
            BaseRect.Width -= Pad.Horizontal
            BaseRect.Height -= Pad.Vertical
            BaseRect.Offset(Pad.Left, Pad.Top)
            Return BaseRect
        End Function

        Private Shared Function AdjustRect(ByVal BaseRect As Rectangle, ByVal Pad As Padding) As Rectangle
            BaseRect.Width -= Pad.Horizontal
            BaseRect.Height -= Pad.Vertical
            BaseRect.Offset(Pad.Left, Pad.Top)
            Return BaseRect
        End Function

        Public Sub New()

        End Sub
    End Class
End Namespace

3 个答案:

答案 0 :(得分:2)

您应该从OnPaint方法中删除GC.CollectOnPaint可以经常被触发,并且触发垃圾收集可能会降低它的速度。

相反,请确保正确处理所有非托管资源,如画笔,笔等。这样你就不必手动触发垃圾收集。

如果您仍有问题,请尝试分析项目。使用Visual Studio的内置工具(如果您不使用Express版本),或使用日期等手动

Dim dStart as Date = Date.Now
PaintALLtheStuff()
Dim dEnd as date = Date.Now
Dim T1 as TimeSpan = DEnd - DStart

这不太舒服,但它通常可以正常工作。这是围绕经常被触发的事件的子部分进行的,并查看一直消耗的内容。

答案 1 :(得分:0)

显然,OnPaint方法因某种原因表现不佳。

尽量避免过多地调用GC.Collect()(删除该行,真正解决您的问题)。只要确保你妥善处理所有对象,让.NET处理剩下的事情。此外,保留本地图形对象更清晰。

Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
    Dim graphics As System.Drawing.Graphics = e.Graphics

    If DesignMode Then
        graphics.CompositingQuality = CompositingQuality.Default
        graphics.InterpolationMode = InterpolationMode.Low
        graphics.SmoothingMode = SmoothingMode.HighSpeed
        graphics.TextRenderingHint = TextRenderingHint.SystemDefault
    Else
        graphics.CompositingQuality = CompositingQuality.HighQuality
        graphics.InterpolationMode = InterpolationMode.High
        graphics.SmoothingMode = SmoothingMode.AntiAlias
        graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit
    End If

    Using b As New SolidBrush(Color)
        graphics.FillRectangle(b, ClientRectangle)
    End Using

    If _mousedown Then
        Using b As New SolidBrush(Color.FromArgb(20, 0, 0, 0))
            graphics.FillRectangle(b, ClientRectangle)
        End Using
    ElseIf _hover Then
        Using b As New SolidBrush(Color.FromArgb(20, 255, 255, 255))
            graphics.FillRectangle(b, ClientRectangle)
        End Using
    End If

    ' Position the imagery and text in the proper location
    If Image IsNot Nothing Then
        Dim imageSizeUse As Size = Image.Size
        Dim textSize As SizeF = e.Graphics.MeasureString(Text, Font)
        Dim textArea As Rectangle = AdjustRect(ClientRectangle, New Padding(0))
        textArea.Width -= imageSizeUse.Width - 4

        Dim imageArea As New RectangleF(textArea.X - imageSizeUse.Width, ClientRectangle.Y, imageSizeUse.Width, imageSizeUse.Height)
        Dim imagept As PointF = ImageLocation(GetStringFormat(ImageAlign), ClientRectangle.Size, imageArea.Size)

        Select Case GetStringFormat(TextAlign).Alignment
            Case StringAlignment.Center
                imagept.X = ClientRectangle.X + ((ClientRectangle.Width - textSize.Width - imageSizeUse.Width) / 2) - 16
                textArea.X = ClientRectangle.X + imageSizeUse.Width
            Case StringAlignment.Near
                imagept.X = ClientRectangle.X + 4
                textArea.X = ClientRectangle.X + imageSizeUse.Width + 4
            Case StringAlignment.Far
                imagept.X = ClientRectangle.X + textArea.Width - textSize.Width - 12
                textArea.X = ClientRectangle.X + imageSizeUse.Width - 8
        End Select

        imagept.Y += ClientRectangle.Y

        If _forceWhite Then
            ' Brightness should be -1 (black) to 0 (neutral) to 1 (white)
            Dim colorMatrixVal As Single()() = { _
               New Single() {1, 0, 0, 0, 0}, _
               New Single() {0, 1, 0, 0, 0}, _
               New Single() {0, 0, 1, 0, 0}, _
               New Single() {0, 0, 0, 1, 0}, _
               New Single() {1, 1, 1, 0, 1}}

            Dim colorMatrix As New ColorMatrix(colorMatrixVal)
            Dim ia As New ImageAttributes

            ia.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap)
            graphics.DrawImage(Image, New Rectangle(CInt(imagept.X), CInt(imagept.Y), Image.Width, Image.Height), 0, 0, Image.Width, Image.Height, GraphicsUnit.Pixel, ia)
        Else
            graphics.DrawImage(Image, imagept.X, imagept.Y, Image.Width, Image.Height)
        End If

        Using currFont As New Font("Verdana", 11)
            graphics.DrawString(Text, currFont, Brushes.White, textArea, GetStringFormat(TextAlign))
        End Using
    Else
        Using currFont As New Font("Verdana", 11)
            Using sf As New StringFormat()
                sf.LineAlignment = StringAlignment.Center
                sf.Alignment = StringAlignment.Center
                graphics.DrawString(Text, currFont, Brushes.White, ClientRectangle, sf)
            End Using
        End Using
    End If

    If Focused Then
        Dim highlightRect As Rectangle = New Rectangle(1, 1, ClientRectangle.Width - 3, ClientRectangle.Height - 3)
        Using highlightPen As Pen = New Pen(Drawing.Color.White)
            highlightPen.Width = 1
            highlightPen.DashStyle = Drawing2D.DashStyle.Dot
            graphics.DrawRectangle(highlightPen, highlightRect)
        End Using
    End If

    ' Let .NET handle the garbage collection
    'GC.Collect()
End Sub

答案 2 :(得分:0)

子类化很可能是您最好的解决方案。看看这个网站......

http://msdn.microsoft.com/en-us/library/system.windows.forms.nativewindow.assignhandle%28v=vs.110%29.aspx

你基本上需要做的是使用AssignHandle函数来控制你的控制然后“听”&#39;在WndProc函数中为该控件生成的Windows消息...有WM_PAINT消息,然后您可以捕获然后调用所有绘图代码....