2009-08-18 4 views
2

Ceci est un problème d'application WinForm C#.DataGridView n'appelle pas la méthode Paint lorsque InvalidateCell est appelée

J'ai un DataGridView et j'ai besoin d'un type personnalisé de DataGridViewColumn de sorte que lorsque ma souris est sur une cellule de cette colonne, la cellule y peint quelque chose de spécial. J'ai trouvé a way de surcharger le DataGridViewTextBoxCell pour faire la peinture moi-même. Cet article montre un exemple d'implémentation d'une cellule de roll-over de telle sorte que lorsque vous déplacez votre souris sur une cellule, elle dessine un rectangle rouge autour des limites de sa propre cellule.

Si vous voyez l'exemple, vous découvrirez que la façon dont l'exemple remplit les données est de créer directement des lignes dans la grille. Lorsque j'utilise la liaison de données plutôt que le remplissage direct de lignes, je trouve que les cellules ne se peignent pas elles-mêmes au début. En fait, vous devez d'abord sélectionner une cellule, puis toutes les cellules de cette ligne seront peintes correctement. Si vous ne sélectionnez pas une cellule d'une ligne, toutes les cellules de cette ligne ne seront pas peintes en conséquence lorsque la souris les dépasse.

Je pense qu'il s'agit d'une sorte d'optimisation de la grille de sorte que lorsque vous sélectionnez une cellule, l'objet sous-jacent de cette ligne est activé et la grille appelle la méthode Paint lorsque la méthode InvlidateCell est appel. Mais si l'objet sous-jacent d'une ligne n'est pas activé, la grille va simplement peindre les cellules par défaut pour gagner du temps.

De toute évidence, je n'ai pas besoin de l'optimisation mais de la lenteur. Cela n'a pas d'importance dans mon cas car mes données sur cette grille ne deviennent jamais trop grandes. Comment puis-je y arriver? J'essaye d'appeler grid.Refresh() après que les données soient liées à la grille mais cela n'aide pas.

Nous vous remercions de votre suggestion.

Ji

+0

Si je mets this.DataGridView.Refresh() dans les méthodes OnMouseEnter et OnMouseLeave, le problème est résolu. Mais cela provoque le clignotement de toute la grille pendant que la souris bouge dessus. Je crois que ce n'est pas une bonne solution. – Steve

Répondre

0

Pas tout à fait sûr J'ai compris votre question. Il suffit de voir si cela est un peu comme ce que vous avez besoin:

bool bSomeFlag = false; 
int iCol = 0; 
int iRow = 0; 
private void dataGridView1_CellMouseMove(object sender, DataGridViewCellMouseEventArgs e) { 
      iCol = e.ColumnIndex; 
      iRow = e.RowIndex; 
      bSomeFlag = true; 
      this.dataGridView1.Invalidate(); 
     } 
private void dataGridView1_Paint(object sender, PaintEventArgs e) { 
      if (bSomeFlag && iRow >=0 && iCol>=0) { 
       dataGridView1.Rows[iRow].Cells[iCol].Style.BackColor = Color.Red; 
      } 
     } 
+0

Ce que je veux dire, c'est que si vous appelez la méthode InvalidateCell dans l'événement OnMouseEnter redéfini de la cellule personnalisée, chaque fois que la méthode InvalidateCell est appelée, la méthode Paint de l'objet de cellule doit également être appelée. Mais ce n'est pas vrai si vous utilisez la liaison de données sur la grille. Pour la liaison de données, la méthode Initial InvalidateCell ne déclenchera pas la méthode Paint. Cela ne se produit que si vous sélectionnez une cellule. Une fois qu'une cellule est sélectionnée, toutes les cellules de sa rangée se comportent normalement: La méthode InvalidateCell déclenche toujours la méthode Paint. J'ai déjà essayé votre suggestion. Il va clignoter la cellule pendant le déplacement de la souris, ce qui est mauvais – Steve

0

J'ai eu du mal avec la même question pendant un certain temps, le problème est que toute méthode dans DataGridViewImageButtonCell : DataGridViewTextBoxCell est appelée avec attribut d'objet RowIndex = -1 donc InvalidateCell() obtient déclenché avec rowIndex = -1 afin que rien ne se passe.

Ceci est causé par rows being shared:

Lorsque la propriété RowIndex renvoie -1, la cellule est soit un en-tête de colonne ou la ligne de la cellule est partagée.

MSDN shows some ways comment vous pouvez garder les lignes partagées (allant ainsi contre eux = ligne unshare), y compris:

Par exemple, une ligne ne peut pas être partagée dans l'une des situations suivantes:

  • La ligne contient une seule cellule sélectionnée qui ne se trouve pas dans une colonne sélectionnée.
  • La ligne contient une cellule avec son jeu de propriétés ToolTipText ou ContextMenuStrip.
  • La ligne contient un DataGridViewComboBoxCell avec sa propriété Items.

...

Ne pas manipuler la DataGridViewRowCollection.CollectionChanged ou DataGridView.RowStateChanged événements. Ces événements provoquent le non-partage des lignes. En outre, n'appelez pas les méthodes DataGridViewRowCollection.OnCollectionChanged ou DataGridView.OnRowStateChanged, qui déclenchent ces événements.

J'ai essayé d'utiliser:

public MyDataGridView() 
    : base() 
{ 
    RowStateChanged += MyDataGridView_RowStateChanged; 
} 

void MyDataGridView_RowStateChanged(object sender, 
     DataGridViewRowStateChangedEventArgs e) 
{ 
} 

Il a travaillé, mais je détestais l'idée de lignes par défaut Annulation du partage, donc j'ai finir par étendre ma classe Cell par surcharge:

Code de travail Donc finale ressemble à:

/// <summary> 
/// Required correcting mousve hover displaying 
/// </summary> 
/// <param name="rowIndex"></param> 
/// <returns></returns> 
protected override bool MouseEnterUnsharesRow(int rowIndex) 
{ 
    return true; 
} 

/// <summary> 
/// Required correcting mousve hover displaying 
/// </summary> 
/// <param name="rowIndex"></param> 
/// <returns></returns> 
protected override bool MouseLeaveUnsharesRow(int rowIndex) 
{ 
    return true; 
} 
Questions connexes