Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

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

Posted on 2006-05-28
6
Medium Priority
?
225 Views
Last Modified: 2008-02-01
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
0
Comment
Question by:meninga
  • 2
3 Comments
 
LVL 96

Accepted Solution

by:
Bob Learned earned 2000 total points
ID: 16785085
Here is a class that I use to prevent flicker:

Imports System.Runtime.InteropServices
Imports System.ComponentModel

Public Class NativeMethods

  <DllImport("user32.dll", CharSet:=CharSet.Auto)> _
  Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Int32, ByVal wParam As Int32, ByVal lParam As Int32) As IntPtr
  End Function  'SendMessage

  <Description("Set whether the control will repaint itself.")> _
  Public Shared Sub SetRedraw(ByVal handle As IntPtr, ByVal redraw As Boolean)
    Const WM_SETREDRAW As Integer = &HB

    SendMessage(handle, WM_SETREDRAW, redraw, 0)
  End Sub

End Class

Example:
  NativeMethods.SetRedraw(Me.Panel1.Handle, False)
  ' Do stuff here  ...
  NativeMethods.SetRedraw(Me.Panel1.Handle, True)

Bob
0
 

Author Comment

by:meninga
ID: 16787460
thanks TheLearnedOne.

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

cheers



0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 16788796
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
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: jpaulino
XML Literals are a great way to handle XML files and the community doesn’t use it as much as it should.  An XML Literal is like a String (http://msdn.microsoft.com/en-us/library/system.string.aspx) Literal, only instead of starting and ending with w…
Well, all of us have seen the multiple EXCEL.EXE's in task manager that won't die even if you call the .close, .dispose methods. Try this method to kill any excels in memory. You can copy the kill function to create a check function and replace the …
This video shows how to quickly and easily deploy an email signature for all users in Office 365 and prevent it from being added to replies and forwards. (the resulting signature is applied on the server level in Exchange Online) The email signat…
Enter Foreign and Special Characters Enter characters you can't find on a keyboard using its ASCII code ... and learn how to make a handy reference for yourself using Excel ~ Use these codes in any Windows application! ... whether it is a Micr…
Suggested Courses

581 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question