2009-05-15 4 views
3

J'ai un contrôle DataGridView dans une application de formulaires Windows. Il y a quatre colonnes avec des données de chaîne et trois avec des données DateTime. J'ajoute les lignes par programme en utilisant la méthode Rows.Add(). Toutes les colonnes ont le SortMode défini sur Automatique. En cliquant sur les en-têtes de colonne pour trier fonctionne seulement, à l'exception de la colonne DateTime qui a des nulls. Lorsque l'utilisateur clique sur l'en-tête de cette colonne, il déclenche une exception ArgumentException: l'objet doit être de type DateTime.Tri DataGridView avec des valeurs nulles dans la colonne DateTime

Je connais la difficulté de contourner ce problème: définir tous les SortModes sur NotSortable, en gérant l'événement ColumnHeaderMouseClick et en triant le tout manuellement. Je cherche la voie facile.

Existe-t-il une propriété ou quelque chose que je peux définir, ou une autre manière relativement simple de permettre à cette colonne de trier avec des valeurs nulles?

+0

Si DataGridView est DataBound..SortCompare ne fonctionne pas. Y a-t-il une autre alternative pour cela? –

Répondre

2

Voici la solution que j'ai trouvée. DataGridView déclenche un événement SortCompare que vous pouvez utiliser pour entrer un tri personnalisé. Je gère cet événement et rend les valeurs NULL triées plus haut que les valeurs non NULL (vous pourriez tout aussi bien faire des NULL plus bas que des NULs). Voici le code VB. Je suppose chaque valeur de la cellule est IComparable (sinon elle sera traitée par la logique de gestion des erreurs normale.)

Try 
    If e.CellValue1 Is Nothing OrElse e.CellValue1.Equals(DBNull.Value) Then 
     If e.CellValue2 Is Nothing OrElse e.CellValue2.Equals(DBNull.Value) Then 
      e.SortResult = 0 
     Else 
      e.SortResult = 1 
     End If 
    Else 
     If e.CellValue2 Is Nothing OrElse e.CellValue2.Equals(DBNull.Value) Then 
      e.SortResult = -1 
     Else 
      e.SortResult = DirectCast(e.CellValue1, IComparable).CompareTo(DirectCast(e.CellValue2, IComparable)) 
     End If 
    End If 
    e.Handled = True 
Catch ex As Exception 
    HandleError("Error sorting result grid values", ex) 
    Close() 
End Try 

Si quelqu'un a des améliorations sur ce s'il vous plaît ne hésitez pas à les poster.

+0

Voir ma réponse mise à jour. Si ce que vous avez posté résout votre problème, cool. Mais je suis intéressé de savoir si ma suggestion fonctionne aussi pour vous. –

+0

Si DataGridView est DataBound..SortCompare ne fonctionne pas. Y a-t-il une autre alternative pour cela? –

1

Si vous ajoutez dynamiquement des lignes, je dois supposer que DataGridView n'est pas Databound. Dans ce cas, pourquoi ne vérifiez-vous pas les valeurs nulles lorsque vous remplissez les cellules de ligne correspondantes et instanciez une sorte de date fictive (une date amusante dans le passé pour indiquer qu'il s'agit d'une valeur nulle?) pour que le tri soit bon.

Si ce n'est pas bon - qu'en est-il de créer votre propre DataGridView exactement le même que celui intégré (en utilisant l'héritage) BUT surchargeant la méthode de tri pour ignorer les valeurs nulles?

+0

Vous avez raison, ce n'est pas DataBound. C'est une bonne suggestion, mais je préférerais garder les valeurs nulles à l'écran si je le peux. Je vais garder cela comme plan B. –

+0

Mmm, ok - qu'en est-il de la nouvelle suggestion? voir edit – JohnIdol

+0

Je peux donner un coup de feu. Ce n'est probablement pas moins de travail que de gérer manuellement le tri, mais ce serait au moins plus intéressant. –

1

Mise à jour Réponse: Après avoir regardé votre réponse affichée, je vois que vous vérifiez DBNull.Value dans les cellules. Cela peut être la source de votre problème car DBNull.Value ne peut pas être converti en DateTime. Si vous ajoutez par programme les lignes, essayez de remplacer DBNull.Value par null (Nothing).


Réponse Original: Essayez de faire cela pour chaque colonne qui contient les données DateTime, de préférence avant que les données sont chargées:

myDateTimeColumn.ValueType = GetType(DateTime) 

Selon MSDN, la propriété ValueType est « utilisé lors du filtrage ou trier les colonnes par rapport au contenu de leurs cellules. " Donc, je serais sûr de le définir pour toute colonne qui permet le tri.

Avec cette propriété, la grille peut être triée sur une colonne qui a des valeurs nulles et forcera les cellules insérées/mises à jour à être converties en DateTime.

+0

Merci pour ce message. Je définis les colonnes dans le concepteur au lieu de programmer, et j'ai plusieurs colonnes. Je me demande si l'une ou l'autre de ces deux différences pourrait expliquer les résultats différents. –

0

Juste pour ajouter du code à cette question ...Je l'ai fait ce qui suit pour faire le tri pour fonctionner correctement pour DateTime (et d'autres types non-cordes) en présence de valeurs nulles:

public MyFormCTor() { 
    ... 
    m_dataGridView.SortCompare += MySortCompare; 
    ... 
} 

... 

static void MySortCompare(object sender, DataGridViewSortCompareEventArgs e) 
{ 
    if (e.CellValue1 == e.CellValue2) 
    { 
     e.SortResult = 0; 
     return; 
    } 

    if (e.CellValue1 == null) 
    { 
     e.SortResult = -1; 
     return; 
    } 

    if (e.CellValue2 == null) 
    { 
     e.SortResult = 1; 
     return; 
    } 

    e.SortResult = ((IComparable)e.CellValue1).CompareTo(e.CellValue2); 
} 
4

Une solution simple est d'ajouter une fonction « tonull », que vous exécutez l'e .cellvalue1 et 2 à chaque fois qu'une comparaison est faite. Si la valeur est "" alors la valeur de la cellule sera changée en 01/01/1001 si vous voulez que les valeurs nulles apparaissent en premier sur le tri ou 01/01/3001 ou quelque chose ridiculement haut si vous voulez qu'elles apparaissent en dernier sur le genre.

Private Sub dgvTable_SortCompare(ByVal sender As Object, ByVal e As DataGridViewSortCompareEventArgs) Handles dgvTable.SortCompare 

    If e.Column.Index = 4 Then 

     e.SortResult = System.DateTime.Compare(todatenull(e.CellValue1), todatenull(e.CellValue2)) 

    End If 

    e.Handled = True 
End Sub 


Function todatenull(ByVal cellvalue) 
    If cellvalue = "" Then 
     Return "01/01/1001" 
    Else 
     Return cellvalue 
    End If 
End Function 
Questions connexes