Link to home
Start Free TrialLog in
Avatar of meninga
meninga

asked on

Link labels flickerin form panel when the form receives focus or is restored.

I have added a series of link label controls to a panel control in a windows application. The form cannot be maximised or resized but when it loses focus- regains focus or is minimised and then restored, the link labels on the panel flicker.

The link labels are only added to the panel when it is created yet the flickering still occurs. I have recently upgraded to framework 2.0 and whilst this problem existed in framework 1.0, it has become more noticeable in framework 2.0 as each link seems to be repainted individually when the form is restored.

I have attached the code below including the entry required in the exe.config file to switch between framework 1.0 and framework 2.0.

Exe Config entry is:
<configuration>
      <startup>
            <supportedRuntime version="v2.0.50727"/>            
            <requiredRuntime version="v2.0.50727"/>
      </startup>
</configuration>

Sample code is:
Imports SDD = System.Drawing.Drawing2D
Imports ST = System.Threading
Imports SX = System.Xml

Public Class Form1
    Inherits System.Windows.Forms.Form

    Protected _selectedCategoryLink As MyCategoryLinkLabel
    Friend WithEvents panelLinksBackground As System.Windows.Forms.Panel
    Friend WithEvents Panel1 As System.Windows.Forms.Panel
    Protected _applicationLinkCount As Integer

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call

    End Sub

    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub
    Friend WithEvents panelCategory As ACFlickering.FilledPanel
    Friend WithEvents lblLinkHeader As System.Windows.Forms.Label
    Friend WithEvents panelLinks As System.Windows.Forms.Panel
    Friend WithEvents panelLine As System.Windows.Forms.Panel
    Friend WithEvents picLogo As System.Windows.Forms.PictureBox
    Friend WithEvents picWelcome As System.Windows.Forms.PictureBox
    Friend WithEvents menuBackup As System.Windows.Forms.MenuItem

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    Friend WithEvents ImageList1 As System.Windows.Forms.ImageList
    Friend WithEvents picClientTools As System.Windows.Forms.PictureBox
    Friend WithEvents picBusinessTools As System.Windows.Forms.PictureBox
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.components = New System.ComponentModel.Container()
        Dim resources As System.Resources.ResourceManager = New System.Resources.ResourceManager(GetType(Form1))
        Me.panelLinksBackground = New System.Windows.Forms.Panel()
        Me.Panel1 = New System.Windows.Forms.Panel()
        Me.panelLinks = New System.Windows.Forms.Panel()
        Me.panelCategory = New ACFlickering.FilledPanel()
        Me.picBusinessTools = New System.Windows.Forms.PictureBox()
        Me.picClientTools = New System.Windows.Forms.PictureBox()
        Me.ImageList1 = New System.Windows.Forms.ImageList(Me.components)
        Me.panelLinksBackground.SuspendLayout()
        Me.panelCategory.SuspendLayout()
        Me.SuspendLayout()
        '
        'panelLinksBackground
        '
        Me.panelLinksBackground.Controls.AddRange(New System.Windows.Forms.Control() {Me.Panel1})
        Me.panelLinksBackground.Location = New System.Drawing.Point(315, 85)
        Me.panelLinksBackground.Name = "panelLinksBackground"
        Me.panelLinksBackground.Size = New System.Drawing.Size(186, 202)
        Me.panelLinksBackground.TabIndex = 1
        '
        'Panel1
        '
        Me.Panel1.BackColor = System.Drawing.Color.Black
        Me.Panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
        Me.Panel1.CausesValidation = False
        Me.Panel1.ForeColor = System.Drawing.Color.Black
        Me.Panel1.Location = New System.Drawing.Point(21, 114)
        Me.Panel1.Name = "Panel1"
        Me.Panel1.Size = New System.Drawing.Size(152, 2)
        Me.Panel1.TabIndex = 16
        Me.Panel1.Visible = False
        '
        'panelLinks
        '
        Me.panelLinks.Name = "panelLinks"
        Me.panelLinks.TabIndex = 0
        '
        'panelCategory
        '
        Me.panelCategory.Controls.AddRange(New System.Windows.Forms.Control() {Me.picBusinessTools, Me.picClientTools})
        Me.panelCategory.GradientEndColour = System.Drawing.Color.Empty
        Me.panelCategory.GradientMode = System.Drawing.Drawing2D.LinearGradientMode.Horizontal
        Me.panelCategory.GradientStartColour = System.Drawing.Color.Empty
        Me.panelCategory.Location = New System.Drawing.Point(27, 12)
        Me.panelCategory.Name = "panelCategory"
        Me.panelCategory.Size = New System.Drawing.Size(240, 316)
        Me.panelCategory.TabIndex = 0
        Me.panelCategory.Wallpaper = Nothing
        '
        'picBusinessTools
        '
        Me.picBusinessTools.BackColor = System.Drawing.Color.Transparent
        Me.picBusinessTools.Image = CType(resources.GetObject("picBusinessTools.Image"), System.Drawing.Bitmap)
        Me.picBusinessTools.Location = New System.Drawing.Point(24, 152)
        Me.picBusinessTools.Name = "picBusinessTools"
        Me.picBusinessTools.Size = New System.Drawing.Size(120, 24)
        Me.picBusinessTools.TabIndex = 21
        Me.picBusinessTools.TabStop = False
        '
        'picClientTools
        '
        Me.picClientTools.BackColor = System.Drawing.Color.Transparent
        Me.picClientTools.Image = CType(resources.GetObject("picClientTools.Image"), System.Drawing.Bitmap)
        Me.picClientTools.Location = New System.Drawing.Point(32, 32)
        Me.picClientTools.Name = "picClientTools"
        Me.picClientTools.Size = New System.Drawing.Size(104, 24)
        Me.picClientTools.TabIndex = 19
        Me.picClientTools.TabStop = False
        '
        'ImageList1
        '
        Me.ImageList1.ColorDepth = System.Windows.Forms.ColorDepth.Depth8Bit
        Me.ImageList1.ImageSize = New System.Drawing.Size(16, 16)
        Me.ImageList1.ImageStream = CType(resources.GetObject("ImageList1.ImageStream"), System.Windows.Forms.ImageListStreamer)
        Me.ImageList1.TransparentColor = System.Drawing.Color.Transparent
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(528, 380)
        Me.Controls.AddRange(New System.Windows.Forms.Control() {Me.panelLinksBackground, Me.panelCategory})
        Me.MaximizeBox = False
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.panelLinksBackground.ResumeLayout(False)
        Me.panelCategory.ResumeLayout(False)
        Me.ResumeLayout(False)

    End Sub


    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Try
         
            Me._selectedCategoryLink = Nothing
            Dim offset As Integer = Me.panelCategory.Left

            Me.Width = 640
            Me.Height = 480

            Dim alignLogo As String = "TopLeft"

            Me.panelCategory.GradientStartColour = Color.FromArgb(0, 0, 77)
            Me.panelCategory.GradientEndColour = Color.FromArgb(0, 0, 204)
            Me.panelCategory.GradientMode = SDD.LinearGradientMode.Vertical
            Me.panelCategory.Top = 50 + offset
            Me.panelCategory.Height = 360

            Me.panelLinksBackground.Visible = False

            Me.panelLinksBackground.Top = 60
            Me.panelLinksBackground.Height = 360
            Me.panelLinksBackground.Left = 230
            Me.panelLinksBackground.Width = 394

            Dim startX As Integer = 0
            Dim startY As Integer = 0

            Me.picClientTools.Left = offset
            Me.picClientTools.Top = offset

            Me.picBusinessTools.Left = offset

            startX = offset
            startY = 8 + 21 + offset

            Dim i As Long = 0
            Dim y As Integer = 0

            For y = 1 To 2

                For i = 0 To 5

                    Dim myLL As New MyCategoryLinkLabel(Me.ImageList1, 6, 7)
                    myLL.Name = "myLL" & i
                    myLL.Text = "Prospecting"
                    myLL.ToolTip = "Prospecting Tools"
                    myLL.Location = New Point(startX, startY)
                    myLL.TheColor = Color.White

                    myLL.CategoryKey = "Business Tools"
                    myLL.ApplicationGroupKey = "Growing the Business"

                    'AddHandler myLL.CategoryLinkClick, AddressOf Me.MyCategoryLinkHandler
                    Me.panelCategory.Controls.Add(myLL)

                    startY += myLL.Height    '+      2

                Next

                If 0 >= 0 Then  '      client      tools      finished, position business tols bmp

                    Me.picBusinessTools.Top = 177
                    startY = 206

                End If

            Next

        Catch ex As Exception
        Finally
            Cursor.Current = Cursors.Default
        End Try

    End Sub

    Protected Function GetWelcomText() As String
        Return ""
    End Function

End Class

Public Class FilledPanel
    Inherits System.Windows.Forms.Panel

    Protected _gradientStartColour As Color  'Gradient fill starting colour
    Protected _gradientEndColour As Color    'Gradient fill ending colour
    Protected _gradientMode As SDD.LinearGradientMode 'Gradient fill mode

    Protected _wallpaper As Image

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call
        Me.SetStyle(ControlStyles.DoubleBuffer, True)
    End Sub

    'UserControl overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        components = New System.ComponentModel.Container()
    End Sub

    Protected Overrides Sub Finalize()
        If Not (Me.BackgroundImage Is Nothing) Then
            Dim oldImage As Image = Me.BackgroundImage
            Me.BackgroundImage = Nothing
            oldImage.Dispose()
        End If

        MyBase.Finalize()
    End Sub

    Public Property GradientStartColour() As Color
        Get
            Return _gradientStartColour
        End Get
        Set(ByVal Value As Color)
            _gradientStartColour = Value
        End Set
    End Property 'GradientStartColour

    Public Property GradientEndColour() As Color
        Get
            Return _gradientEndColour
        End Get
        Set(ByVal Value As Color)
            _gradientEndColour = Value
        End Set
    End Property 'GradientEndColour

    Public Property GradientMode() As SDD.LinearGradientMode
        Get
            Return _gradientMode
        End Get
        Set(ByVal Value As SDD.LinearGradientMode)
            _gradientMode = Value
        End Set
    End Property 'GradientStartColour

    Public Property Wallpaper() As Image
        Get
            Return _wallpaper
        End Get
        Set(ByVal Value As Image)
            _wallpaper = Value
            Me.BackgroundImage = Me._wallpaper
        End Set
    End Property 'wallpaper

    Private Sub FilledPanel_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Resize

        Try

            If (Me.Width > 0) And (Me.Height > 0) Then
                If Me._wallpaper Is Nothing Then ' draw the wall paper as the background image

                    Dim oldImage As Image = Me.BackgroundImage
                    If Not oldImage Is Nothing Then
                        'Do Nothing
                    Else
                        ' Create a Linear Gradient Brush to paint the background
                        Dim myLinearGradientBrush As SDD.LinearGradientBrush = _
                                     New SDD.LinearGradientBrush( _
                                     Me.DisplayRectangle, _
                                     _gradientStartColour, _
                                     _gradientEndColour, _
                                     _gradientMode)

                        ' Paint on a temp image to minimise flickering
                        Dim tmpImage As Bitmap = New Bitmap(Me.Width, Me.Height)
                        Dim myGraphics As Graphics = Graphics.FromImage(tmpImage)

                        myGraphics.FillRectangle(myLinearGradientBrush, 0, 0, tmpImage.Width, tmpImage.Height)

                        ' Update the background image

                        Me.BackgroundImage = tmpImage

                        ' dispose of old image if exists
                        If Not (oldImage Is Nothing) Then
                            oldImage.Dispose()
                        End If

                        ' More dispose
                        myLinearGradientBrush.Dispose()
                        myGraphics.Dispose()

                    End If
                End If
            End If

        Catch ex As Exception
        End Try

    End Sub

End Class

Public Class MyCategoryLinkLabel
    'Inherits System.Windows.Forms.UserControl
    Inherits System.Windows.Forms.LinkLabel

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call

        Me.Init(Nothing, 0, 0)

    End Sub

    'UserControl overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        components = New System.ComponentModel.Container()
    End Sub

    Public Event CategoryLinkClick(ByVal sender As MyCategoryLinkLabel, ByVal theText As String)


    '' the text the user set to this control before it gets mangled
    Protected _originalText As String = ""

    '' image list indexs for2 pictures for this control to display
    Protected _picIndex As Integer = 0
    Protected _altIndex As Integer = 0

    '' tooltip for this control
    Protected _toolTip As ToolTip

    ' model for this view
    Protected _categoryKey As String
    Protected _applicationGroupKey As String

    Public Sub New(ByVal imageList As ImageList, ByVal picIndex As Integer, ByVal altIndex As Integer)

        MyBase.New()
        InitializeComponent()
        Me.Init(imageList, picIndex, altIndex)

    End Sub

    Protected Overridable Sub Init(ByVal imageList As ImageList, ByVal picIndex As Integer, ByVal altIndex As Integer)

        Me.ImageList = imageList
        Me.ImageIndex = picIndex

        Me._picIndex = picIndex
        Me._altIndex = altIndex

        Me.ActiveLinkColor = Color.White
        Me.AutoSize = False
        Me.BackColor = Color.Transparent
        Me.BorderStyle = BorderStyle.None
        Me.DisabledLinkColor = Color.White
        Me.Dock = DockStyle.None
        Me.FlatStyle = FlatStyle.Flat

        'Me.Font = New Font("Arial", 9, FontStyle.Regular, GraphicsUnit.Point)
        Me.Font = New Font("Verdana", 9, FontStyle.Regular, GraphicsUnit.Point)

        Me.ForeColor = Color.White
        Me.UseMnemonic = False
        Me.Visible = True
        Me.VisitedLinkColor = Color.White
        Me.TextAlign = ContentAlignment.MiddleLeft
        Me.LinkBehavior = LinkBehavior.NeverUnderline
        Me.LinkColor = Color.White
        Me.ImageAlign = ContentAlignment.MiddleLeft

        Me._toolTip = New ToolTip()

        Me._toolTip.SetToolTip(Me, "")
        Me._toolTip.ShowAlways = True


    End Sub

    Public Property ToolTip() As String
        Get
            Return Me._toolTip.GetToolTip(Me)
        End Get
        Set(ByVal Value As String)
            Me._toolTip.SetToolTip(Me, Value)
        End Set
    End Property

    Public Overrides ReadOnly Property Focused() As Boolean

        ' maybe we should be using Control.ShowFocusCues = false ???

        Get
            Return False
        End Get

    End Property


    Public WriteOnly Property TheColor() As Color
        Set(ByVal Value As Color)

            MyBase.ActiveLinkColor = Value
            MyBase.DisabledLinkColor = Value
            MyBase.ForeColor = Value
            MyBase.LinkColor = Value
            MyBase.VisitedLinkColor = Value

        End Set
    End Property


    Public Property CategoryKey() As String
        Get
            Return _categoryKey
        End Get

        Set(ByVal Value As String)
            _categoryKey = Value
        End Set

    End Property



    Public Property ApplicationGroupKey() As String
        Get
            Return _applicationGroupKey
        End Get

        Set(ByVal Value As String)
            _applicationGroupKey = Value
        End Set

    End Property
    Public ReadOnly Property PicIndex() As Integer
        Get
            Return _picIndex
        End Get
    End Property

    Public ReadOnly Property AltIndex() As Integer
        Get
            Return _altIndex
        End Get
    End Property

    Public Overrides Property Text() As String

        Get
            Return MyBase.Text
        End Get

        Set(ByVal Value As String)

            ' size the control based on the text value and the font

            Me._originalText = Value
            If Value = "" Then Value = "_"

            Dim img As Image = Nothing ' the picture to draw

            Dim gr As Graphics = Me.CreateGraphics

            Try

                ' see if there is a valid picture

                If Not Me.ImageList Is Nothing Then
                    If Me.ImageList.Images.Count > 0 Then
                        If Me.ImageIndex < Me.ImageList.Images.Count Then
                            img = Me.ImageList.Images(Me.ImageIndex)
                        End If
                    End If
                End If

                If img Is Nothing Then ' text only, no image

                    MyBase.Text = Value

                    Dim textSize As Size = gr.MeasureString(MyBase.Text & "_____", Me.Font).ToSize
                    Me.Size = New Size(CType(Math.Ceiling(textSize.Width + 1), Integer), Me.Font.Height + 2)

                Else ' there is a picture to show as well as text

                    ' number of spaces required

                    Dim spaceSize As Size = gr.MeasureString(" ", Me.Font).ToSize
                    Dim spacesReqd As Double = Math.Ceiling(img.Width / spaceSize.Width + 1) + 1
                    Dim spaces As String = New String(" "c, CType(spacesReqd, Integer))

                    MyBase.Text = spaces & Value

                    Dim textSize As SizeF = gr.MeasureString(MyBase.Text & "_____", Me.Font)
                    Me.Size = New Size(CType(Math.Ceiling(textSize.Width + 1), Integer), _
                                        Math.Max(Me.Font.Height, img.Height) + 2)

                    Me.LinkArea = New LinkArea(spaces.Length, Value.Length)

                End If

            Catch ex As Exception
                Throw ex
            End Try

            gr.Dispose()

        End Set

    End Property

End Class
ASKER CERTIFIED SOLUTION
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of meninga
meninga

ASKER

thanks TheLearnedOne.

Where in my code sample above would you suggest I call the setredraw method?

cheers



That is a great question, but one without an answer.

I did notice, though, that with double-buffering, you need this:

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

Bob