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.