J'essaie actuellement de copier les lignes sélectionnées d'un DataGridView vers un autre.
J'essaie de capturer la valeur de la CheckBox, où si elle est cochée, la ligne entière sera copiée dans un autre DataGridView.
Par exemple, comme ajouter au panier puis revoir le panier. J'ai fait référence au message suivant:
Cependant, cela ne semble pas aider.
J'ai essayé d'utiliser une boucle For comme celle ci-dessous, mais je ne sais pas trop comment procéder.
Private Sub AppendColumnsToDGV2()
Dim dt As New DataTable
'dt.Columns.Add(CreateDGVCheckBoxCol())
'dt.Columns.Add(CreateImageColumn())
dt.Columns.Add(DataGridView1.Columns(3).HeaderText)
dt.Columns.Add(DataGridView1.Columns(4).HeaderText)
dt.Columns.Add(DataGridView1.Columns(5).HeaderText)
dt.Columns.Add(DataGridView1.Columns(6).HeaderText)
DataGridView2.DataSource = dt
End Sub
AppendColumnsToDGV2 :
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Dim dt As New DataTable()
AppendColumnsToDGV2()
For Each row As DataGridViewRow In DataGridView1.Rows
If row.Cells("SelectColumn").Value = True Then
Dim NewRow As DataRow
For i As Integer = 0 To row.Cells.Count - 1
NewRow(i) = row.Cells(i).Value
DataGridView2.Rows.Add(NewRow)
Next
End If
Next
Ce que je fais ici ne fonctionne pas et je n'ai aucune idée de la manière de procéder.
Toute aide serait appréciée, merci, gentiment.
Chaque fois que j'exécute ce code, j'obtiens l'erreur:
System.NullReferenceException: La référence d'objet n'est pas définie sur une instance d'un objet
Je ne sais pas comment y remédier.
Voici à quoi ressemble le DataGridView:
3 Réponses :
Vous utilisez actuellement 2 DataTables distincts. Vous essayez également d'ajouter une ligne à chaque fois que vous définissez une valeur de colonne. Cela pourrait fonctionner pour vous.
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Dim dt As New DataTable()
AppendColumnsToDGV2(dt)
For Each row As DataGridViewRow In DataGridView1.Rows
If row.Cells("SelectColumn").Value = True Then
Dim NewRow = dt.NewRow
For i As Integer = 0 To row.Cells.Count - 1
NewRow(i) = row.Cells(i).Value
Next
dt.Rows.Add(NewRow)
End If
Next
End Sub
Private Sub AppendColumnsToDGV2(dt As DataTable)
'dt.Columns.Add(CreateDGVCheckBoxCol())
'dt.Columns.Add(CreateImageColumn())
dt.Columns.Add(DataGridView1.Columns(3).HeaderText)
dt.Columns.Add(DataGridView1.Columns(4).HeaderText)
dt.Columns.Add(DataGridView1.Columns(5).HeaderText)
dt.Columns.Add(DataGridView1.Columns(6).HeaderText)
DataGridView2.DataSource = dt
End Sub
Merci pour ce @JerryM, mais maintenant j'obtiens l'erreur 'Les lignes ne peuvent pas être ajoutées par programme à la collection de lignes de DataGridView lorsque le contrôle est lié aux données.' alors je l'ai changé en datagridview2.datasource.rows.add (newrow) et maintenant j'obtiens l'erreur System.ArgumentException: 'Cette ligne appartient déjà à cette table.'
Oops. Oui. La ligne doit être ajoutée à la table de données. J'ai mis à jour la réponse.
Aussi, lorsque j'utilise dt.rows.add (newrow) , j'obtiens également cette ligne appartient déjà à cette table
J'ai oublié de suivre mes propres conseils sur le déplacement de l'appel de méthode Add ci-dessous, puis l'instruction Next .
Si vous effectuez correctement la liaison de données, vos données sous-jacentes seront mises à jour lorsque la case à cocher est activée. Ensuite, vous pouvez simplement utiliser un certain LINQ. Vous devriez éviter d'itérer sur vos DataGridViewRows chaque fois que possible (ici c'est possible) car ils ne devraient pas contenir les données, mais plutôt les afficher.
Cet exemple simple fonctionne dans un formulaire avec deux DataGridViews et un Button avec des noms par défaut, dans vb .net.
Public Class Form1
Private allProducts As List(Of Product)
Private basketProducts As List(Of Product)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
allProducts = New List(Of Product) From {
New Product() With {.Name = "Fairy Gel", .ID = 1},
New Product() With {.Name = "Fairy Caps", .ID = 2},
New Product() With {.Name = "Fairy Liquid", .ID = 3}}
DataGridView1.DataSource = allProducts
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
basketProducts = allProducts.Where(Function(p) p.Selected).ToList()
DataGridView2.DataSource = basketProducts
End Sub
' dummy class to emulate your data
Private Class Product
Public Property Selected As Boolean
Public Property Name As String
Public Property ID As Long
End Class
End Class
@SchmellerMeller cela ne nécessite aucune extension ni référence supplémentaire au-delà de celles par défaut dans une application WinForms. De quoi parlez-vous précisément?
@SchmellerMeller Dans votre question, vous essayiez d'opérer sur le formulaire plutôt que sur les données sous-jacentes, et je voulais juste souligner que vous devriez opérer sur les données. Voilà comment résoudre le problème. En fait, ma solution est la même que celle de Jimi (ce qui a l'air super car il était au courant de votre question précédente). En général, ma solution résout le problème général posé dans votre question. Jimi's résout votre problème spécifique car il est adapté à votre question précédente.
Ma faute. Je viens de réaliser que c'est fondamentalement exactement la même chose. Oops.
Cette question est strictement liée à la précédente:
Afficher des images dans une colonne DataGridView en utilisant des objets JSON comme DataSource
Vous utilisez une sous-classe ( Résultat ) de RootObject pour remplir le premier DataGridView.
Modifiez la classe Result comme suit:
Selected As Boolean , décorée d'un attribut . SelectionResult ici, une sélection de propriétés de la classe Result que vous pensez être nécessaires dans le deuxième DataGridView pour afficher les produits sélectionnés. Result qui renvoie une sous-section d'elle-même sous forme de SelectionResult objet. Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
SelectedProducts.AddRange(CurrentProducts.
Where(Function(p) p.Selected = True AndAlso
(Not SelectedProducts.Any(Function(sp) sp.ID = p.id))).
Select(Function(p) p.GetSelectionResult()).ToArray())
ResetCart()
End Sub
Private Sub btnRemoveSelection_Click(sender As Object, e As EventArgs) Handles btnRemoveSelection.Click
If DataGridView2.SelectedRows.Count = 0 Then Return
Dim itemsRemoved As Boolean = False
Dim selectedItems() As Integer = DataGridView2.SelectedRows.
OfType(Of DataGridViewRow)().
Select(Function(r) CInt(r.Cells("ID").Value)).ToArray()
For Each ID As Integer In selectedItems
Dim currentIndex As Integer = SelectedProducts.FindIndex(Function(p) p.ID = ID)
If currentIndex >= 0 Then
SelectedProducts.RemoveAt(currentIndex)
itemsRemoved = True
End If
Next
If itemsRemoved Then
ResetCart()
End If
End Sub
Private Sub ResetCart()
DataGridView2.DataSource = Nothing
DataGridView2.DataSource = SelectedProducts
DataGridView2.Columns(0).Visible = False
DataGridView2.AutoResizeRows()
End Sub
List (Of Class) en tant que champs dans le formulaire. La classe principale, dans la question précédente, s'appelait ProductsQuery , donc je réutilise les noms déjà définis ici: CurrentProducts.AddRange(JsonPost.uk.ghs.Products.Results)
Dans la méthode qui remplit le premier DataGridView, initialisez la liste CurrentProducts :
CurrentProducts = New List(Of ProductsQuery.Result)()
Une fois le JSON désérialisé, remplissez la liste avec les résultats JSON:
Private CurrentProducts As List(Of ProductsQuery.Result) = New List(Of ProductsQuery.Result)() Private SelectedProducts As List(Of ProductsQuery.SelectionResult) = New List(Of ProductsQuery.SelectionResult)()
Dans le gestionnaire d'événements du Button qui ajoute les produits sélectionnés au deuxième DataGridView, insérez ce code:
Modifier :
La liste SelectedProducts préserve les éléments sélectionnés dans le premier DataGridView: seuls les éléments qui ne sont pas déjà dans la liste CurrentProducts sont ajoutés à la sélection.
Le bouton btnRemoveSelection supprime les éléments sélectionnés dans le deuxième DataGridView de la liste SelectedProducts . La sélection de la ligne DataGridView est quelque peu lourde, vous pouvez donc souhaiter ajouter une colonne CheckBox pour faciliter la sélection des éléments à supprimer.
Public Class Result
<JsonIgnore>
Public Property Selected As Boolean
'(...)
Public Function GetSelectionResult() As SelectionResult
Return New SelectionResult With {
.ID = Me.id,
.Image = Me.Image,
.Name = Me.Name,
.ProductDescription = Me.ProductDescription,
.Department = Me.Department,
.Price = Me.Price,
.Unitprice = Me.Unitprice
}
End Function
End Class
Public Class SelectionResult
Public Property ID As Integer
Public Property Image As Bitmap
Public Property Name As String
Public Property ProductDescription As String
Public Property Department As String
Public Property Price As Decimal
Public Property Unitprice As Decimal
End Class
Ceci remplit la List (Of SelectedProducs) avec les éléments sélectionnés du premier DataGridView et définit la DataSource de le deuxième DataGridView de cette liste.
Notez que la première colonne de DataGridView est définie sur Visible = False , car cette colonne correspond au ID propriété de l'élément sélectionné
Le GetSelectionResult() de la classe Result renvoie le les valeurs de propriétés définies dans la classe SelectionResult . Vous pouvez bien sûr redéfinir cette classe pour qu'elle contienne toutes les propriétés qui vous conviennent.
Voici le résultat de ces modifications:
Merci pour cela @Jimi savez-vous comment j'obtiendrais réellement les données dans le deuxième DGV pour y rester. J'ai supprimé les lignes DataGridView2.DataSource = Nothing et SelectedProducts.Clear () cependant, il n'y a aucune différence. Chaque fois que je fais une autre recherche, ils sont partis.
Voulez-vous dire que vous voulez que le deuxième DGV conserve les résultats des différentes sélections effectuées à différents moments? En tant que dépôt de choix ou panier de magasin?
Ouais exactement, comme un panier, où tous les résultats sélectionnés restent pour que l'utilisateur final puisse les examiner quand il le souhaite.
Très bien, cela a du sens. Je ferai une retouche dès que j'aurai un moment.
Code mis à jour. J'ai ajouté un deuxième bouton qui permet de supprimer des éléments de la liste de sélection. Lisez les notes. Voyez si cela vous convient.
Exactement ce que j'avais en tête, merci beaucoup @Jimi.
«DataGridView2.Rows.Add (NewRow)» doit suivre la première instruction Next. Avez-vous des erreurs ou ne voyez-vous tout simplement rien se passer?
En outre, newRow doit être construit par le DataTable. Par exemple.
Dim newRow = dt.NewRow.@JerryM J'obtiens l'erreur
System.NullReferenceException: 'La référence d'objet n'est pas définie sur une instance d'un objet.'. J'utilise le datarow lorsqu'une valeur ne lui a apparemment pas été assignée.Vous devez passer dt à la routine AppendColumnsToDGV2. Exemple `Private Sub AppendColumnsToDGV2 (dt As DataTable) '. Vous utilisez actuellement 2 tables de données distinctes.
Utilisez-vous toujours les classes générées à partir du JSON affichées dans votre question précédente ? Si tel est le cas, la solution est vraiment simple.
@Jimi je suis oui, c'est super de te voir xD
Alors, donnez-moi une minute (ou deux :), je vais écrire quelque chose.