Probleme de Paint sur un DataGridViewColumnHeaderCell

Résolu
foliv57 Messages postés 420 Date d'inscription vendredi 17 novembre 2006 Statut Membre Dernière intervention 15 juillet 2014 - 12 mai 2011 à 10:31
foliv57 Messages postés 420 Date d'inscription vendredi 17 novembre 2006 Statut Membre Dernière intervention 15 juillet 2014 - 13 mai 2011 à 10:02
Bonjour à tous,

Je suis face à un problème qui me rend un peut fou.

Je me suis fait une classe "DataGridViewCustomColumnHeaderCell" qui hérite de "DataGridViewColumnHeaderCell" toute simple, qui ne fait qu'afficher un petit carré de couleur en haut à gauche de l'en-tête.

La couleur du carré doit changer à chaque Paint de l'en-tête.

C'est la ou mon problème commence. Si par exemple mon DataGridView contient 4 colonnes. Si je survole avec la sourie la 4ème colonne, l'évènement paint de toutes les en-tetes de colonnes est bien exécuté, mais seul celui de la colonne 4 est rafraichi à l'écran.

J'ai pensais à une histoire de limite de region du graphics lors du paint, mais à priori ce n'est pas le cas, car la région de dessin comprend toute la largeur du DataGridView. J'ai l'impression que c'est le DataGridView qui bloque le rafraichissement uniquement sur une seule en-tête. Le problème est que je ne peut pas demander à ce dernier de rafraichir toutes les en-tetes dans le paint d'une d'elles, car je vous laisse imaginer que ceci provoque une boucle infinie.

Je m'en remet donc à vos lumières, si quelqu'un a déjà rencontré le problème.

Merci d'avance.

Voici donc la classe qui défini mon en-tete custom et une colonne de textboxs avec ce type d'en-tete.
Public Class DataGridViewCustomColumnHeaderCell
    Inherits DataGridViewColumnHeaderCell

    Private rColor As Color

    Protected Overrides Sub Paint(ByVal graphics As System.Drawing.Graphics, ByVal clipBounds As System.Drawing.Rectangle, ByVal cellBounds As System.Drawing.Rectangle, ByVal rowIndex As Integer, ByVal dataGridViewElementState As System.Windows.Forms.DataGridViewElementStates, ByVal value As Object, ByVal formattedValue As Object, ByVal errorText As String, ByVal cellStyle As System.Windows.Forms.DataGridViewCellStyle, ByVal advancedBorderStyle As System.Windows.Forms.DataGridViewAdvancedBorderStyle, ByVal paintParts As System.Windows.Forms.DataGridViewPaintParts)
        MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, dataGridViewElementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts)

        'Inversion de la couleur
        rColor = CType(IIf(rColor.Equals(Color.Red), Color.RoyalBlue, Color.Red), Color)

        'Création du rectangle à dessiner
        Dim rect As Rectangle = cellBounds
        rect.X += 5
        rect.Y += 5
        rect.Width = 10
        rect.Height = 10

        'Dessinne le rectangle
        graphics.FillRectangle(New SolidBrush(rColor), rect)

        'Affichage d'un message sur paint de l'en-tete de colonne 2
        If (Me.ColumnIndex = 1) Then
            Console.WriteLine("{0}.{1} Le carré de la colonne 2 doit être {2}", Now.ToLongTimeString, Now.Millisecond, rColor.ToString)
        End If

    End Sub

End Class

Public Class DataGridViewCustomTextBoxColumn
    Inherits DataGridViewTextBoxColumn

    Public Sub New()
        MyBase.New()
        Me.HeaderCell = New DataGridViewCustomColumnHeaderCell
    End Sub

    Public Sub New(ByVal name As String, ByVal headerText As String)
        Me.New()
        Me.Name = name
        Me.HeaderText = headerText
    End Sub

End Class


Et le code pour ajouter 4 colonnes à un datagridview sur load d'une form
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
       With Me.DataGridView1
            .Columns.Add(New DataGridViewCustomTextBoxColumn("col1", "Colonne 1"))
            .Columns.Add(New DataGridViewCustomTextBoxColumn("col2", "Colonne 2"))
            .Columns.Add(New DataGridViewCustomTextBoxColumn("col3", "Colonne 3"))
            .Columns.Add(New DataGridViewCustomTextBoxColumn("col4", "Colonne 4"))

            For j As Integer = 0 To .Columns.Count - 1
                .Columns(j).Width = 100
            Next

            .ColumnHeadersHeight = Me.DataGridView1.ColumnHeadersHeight * 2
            .ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.BottomRight

        End With
       
End Sub


En affichant les messages de la console on remarque bien que lors du passage de la sourie sur l'en-tete de la colonne 4, la couleur affiché dans le message sur paint de la colonne 2 ne correspond pas à la couleur visible à l'écran.
A voir également:

1 réponse

foliv57 Messages postés 420 Date d'inscription vendredi 17 novembre 2006 Statut Membre Dernière intervention 15 juillet 2014 9
13 mai 2011 à 10:02
Problème résolu.

Voici donc la solution pour les personnes ayant le même souci de partage d'éléments entre colonnes.

Le problème vient bien du DataGridView. C'est lui qui défini quelle région doit être redessinée. Donc, dans mon exemple, même si l'évènement paint est bien lancé pour chaque colonne, seul la zone de l'en-tete de colonne survolée par la sourie est rafraichie.
Ceci est bien visible en tracant l'évènement Paint du DataGridView, le paramètre e.ClipRectangle et limité à la taille de l'en-tete survolée. C'est donc ce paramètre qui empêche les autres en-tetes d'etre redessinées. N'ayant pas touver comment redéfinir ce ClipRectangle, j'ai donc utilisé la technique ci-dessous.

Public Class DataGridViewCustomColumnHeaderCell
    Inherits DataGridViewColumnHeaderCell

    'Couleur partagée entre les colonnes
    Private Shared _rColor As Color

    'Evenement de changement de couleur partagé pour informer toutes les colonnes
    Private Shared Event ColorChange As EventHandler

    'Zone du carré de couleur
    Private _rBounds As Rectangle

    'Changement de couleur
    Public Property rColor As Color
        Get
            Return _rColor
        End Get
        Set(ByVal value As Color)
            _rColor = value
            'Informe toutes les colonnes du changement
            RaiseEvent ColorChange(Me, EventArgs.Empty)
        End Set
    End Property

    'Nouvelle instance
    Public Sub New()
        'Initilaisation de la couleur du carré
        _rColor = Color.RoyalBlue
        'Abonement à l'évènement de changement de couleur
        AddHandler DataGridViewCustomColumnHeaderCell.ColorChange, AddressOf Me_ColorChange
    End Sub

    Private Sub Me_ColorChange(ByVal sender As Object, ByVal e As EventArgs)
        If (Me.DataGridView IsNot Nothing) Then
            'Demande au datagridview de mettre à jour l'affichage du carré
            Me.DataGridView.Invalidate(_rBounds)
        End If
    End Sub

    'Définition des évènements qui changent la couleur
    Protected Overrides Sub OnMouseEnter(ByVal rowIndex As Integer)
        MyBase.OnMouseEnter(rowIndex)
        'Inversion de la couleur
        rColor = CType(IIf(_rColor.Equals(Color.Red), Color.RoyalBlue, Color.Red), Color)
    End Sub
    Protected Overrides Sub OnMouseLeave(ByVal rowIndex As Integer)
        MyBase.OnMouseLeave(rowIndex)
        'Inversion de la couleur
        rColor = CType(IIf(_rColor.Equals(Color.Red), Color.RoyalBlue, Color.Red), Color)
    End Sub

    Protected Overrides Sub Paint(ByVal graphics As System.Drawing.Graphics, ByVal clipBounds As System.Drawing.Rectangle, ByVal cellBounds As System.Drawing.Rectangle, ByVal rowIndex As Integer, ByVal dataGridViewElementState As System.Windows.Forms.DataGridViewElementStates, ByVal value As Object, ByVal formattedValue As Object, ByVal errorText As String, ByVal cellStyle As System.Windows.Forms.DataGridViewCellStyle, ByVal advancedBorderStyle As System.Windows.Forms.DataGridViewAdvancedBorderStyle, ByVal paintParts As System.Windows.Forms.DataGridViewPaintParts)
        MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, dataGridViewElementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts)

        'Création du rectangle à dessiner
        _rBounds = cellBounds
        _rBounds.X += 5
        _rBounds.Y += 5
        _rBounds.Width = 10
        _rBounds.Height = 10

        'Dessinne le rectangle
        graphics.FillRectangle(New SolidBrush(_rColor), _rBounds)

    End Sub

End Class
3
Rejoignez-nous