Copier-Coller dans DataGridView

Résolu
Sam_Placi Messages postés 25 Date d'inscription mercredi 29 juin 2022 Statut Membre Dernière intervention 21 septembre 2022 - Modifié le 20 sept. 2022 à 19:29
Sam_Placi Messages postés 25 Date d'inscription mercredi 29 juin 2022 Statut Membre Dernière intervention 21 septembre 2022 - 21 sept. 2022 à 08:31

Bonjour,

Après la mise au point d'un code test exécutant du Drag-Drop entre DataGridView (la discussion "Drag & Drop entre DataGridView"), je souhaite maintenant faire du Copier-Coller ( <CTRL><C> / <CTRL><V> ) entre ces DGV.

Voici ma procédure de test :

Private Sub DGV_KeyUp(sender As Object, e As KeyEventArgs) Handles DGV1.KeyUp, DGV2.KeyUp
        Dim DGV As DataGridView = CType(sender, DataGridView)
        If e.Control Then
            MessageBox.Show(sender.name)
            If e.KeyCode = Keys.C Then
                Clipboard.SetDataObject(DGV.SelectedRows)
            Else
                If e.KeyCode = Keys.V Then
                    Dim Selection As IDataObject = Clipboard.GetDataObject()
                    For Each R As DataGridViewRow In Selection.GetData(GetType(DataGridViewSelectedRowCollection))
                        DGV.Rows.Add(R)
                    Next
                End If
            End If
        End If
End Sub

Il me semble que seule la partie <CTRL><V> pose un problème. Un Selection.GetDataPresent renvoie True. Mais une erreur "La référence d'objet n'est pas définie à une instance d'un objet." vient à la ligne "For Each R ... ".

Qu'ai-je mal programmé ?

Cordialement,

Sam

10 réponses

dysorthographie Messages postés 44 Date d'inscription jeudi 27 janvier 2022 Statut Membre Dernière intervention 4 octobre 2022 4
Modifié le 20 sept. 2022 à 17:38

Bonjour,

tu cherche un truc comme ça?

 Public Sub PasteClipboard(ByVal _dgv As DataGridView)
        Dim L As Integer = 0, C As Integer = 0
        L = _dgv.SelectedCells.Cast(Of DataGridViewCell)().Select(Function(x) x.RowIndex).Distinct().OrderBy(Function(g) g).First()
        For Each Ligne As String In System.Windows.Forms.Clipboard.GetText.Split(Environment.NewLine)
            C = _dgv.SelectedCells.Cast(Of DataGridViewCell)().Select(Function(x) x.ColumnIndex).Distinct().OrderBy(Function(g) g).First()
            If L >= _dgv.Rows.Count - 1 Then _dgv.DataSource.Rows.Add(_dgv.DataSource.NewRow())
            For Each RC As String In Ligne.Split(Convert.ToChar(Keys.Tab))
               If C <= _dgv.ColumnCount - 1 Then _dgv.DataSource.Rows(L)(C) = RC 
                C += 1
            Next
            L += 1
        Next
    End Sub
1
vb95 Messages postés 3097 Date d'inscription samedi 11 janvier 2014 Statut Non membre Dernière intervention 6 octobre 2022 158
21 sept. 2022 à 07:34

Bonjour 

Une solution : deux DataGridview DGV1 et DGV2 et ce code dans Form1

Attention : ne fonctionne qu'avec 2 colonnes dans les DataGridView .

J'ai pas réussi à récupérer depuis le presse papier une DataGridViewSelectedRowCollection : impossible de caster le contenu du presse papier dans ce type de variable . Je me suis débrouiller autrement .

Public Class Form1

    Private ListCells As List(Of String)

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        ' Pour les tests
        With DGV1
            With .Columns
                .Add("Col1", "Col.1")
                .Add("Col2", "Col.2")
            End With
            With .Rows
                .Add("1", "az")
                .Add("2", "aze")
                .Add("3", "azer")
                .Add("4", "azert")
                .Add("5", "azerty")
            End With
            ' Réglages nécessaires
            .AllowDrop = True
            .SelectionMode = DataGridViewSelectionMode.FullRowSelect
            .ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableWithoutHeaderText
        End With
        With DGV2
            With .Columns
                .Add("Col1", "Col.1")
                .Add("Col2", "Col.2")
            End With
            ' Réglages nécessaires
            .AllowDrop = True
            .SelectionMode = DataGridViewSelectionMode.FullRowSelect
            .ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableWithoutHeaderText
        End With

    End Sub

    ' Faire un copier-coller de DGV1 vers DGV2 ou de DGV2 vers DGV1 
    Private Sub DGV_KeyUp(sender As Object, e As KeyEventArgs) Handles DGV1.KeyUp, DGV2.KeyUp

        Dim DGV As DataGridView = CType(sender, DataGridView)
        If e.Control Then
            If e.KeyCode = Keys.C Then
                ' Copier
                Clipboard.Clear()
                ' on copie toutes les cellules dans le presse papier
                Clipboard.SetText(String.Join(Environment.NewLine, CopieCells(DGV)))
            ElseIf e.KeyCode = Keys.V AndAlso Clipboard.ContainsText(TextDataFormat.Text) = True Then
                ' Coller
                Dim Chaine As String = Clipboard.GetText()
                Dim Cells As List(Of String) = Chaine.Split(Environment.NewLine.ToCharArray).ToList
                Cells = Cells.FindAll(Function(p) p <> String.Empty)
                ColleCells(If(DGV.Name = "DGV1", DGV2, DGV1), Cells)
                DGV1.ClearSelection()
                DGV2.ClearSelection()
            End If
        End If

    End Sub

    ''' <summary>
    ''' Colle les cellules dans la DGV de destination
    ''' </summary>
    ''' <param name="DGV"></param>
    ''' <param name="Cells"></param>
    Private Sub ColleCells(DGV As DataGridView, Cells As List(Of String))

        Dim IndexCell As Integer = Cells.Count - 1
        For i = (Cells.Count \ 2) - 1 To 0 Step -1
            DGV.Rows.Add(Cells(IndexCell - 1), Cells(IndexCell))
            IndexCell -= 2
        Next

    End Sub

    ' Copie les lignes sélectionnées dans la DataGridview source
    Private Function CopieCells(DGV As DataGridView) As List(Of String)

        ListCells = New List(Of String)
        For Each Cell As DataGridViewCell In DGV.SelectedCells
            ListCells.Add(Cell.Value.ToString)
        Next
        Return ListCells

    End Function

End Class

1
Sam_Placi Messages postés 25 Date d'inscription mercredi 29 juin 2022 Statut Membre Dernière intervention 21 septembre 2022 1
20 sept. 2022 à 17:51

Merci dysorthographie,

Je connais déjà ce code mais je voulais quelque chose de "plus automatique". Je souhaiterais que ce soit comme avec le Drag-Drop où je peux passer une sélection de plusieurs lignes du DGV et récupérer des "Rows" entières (non Cell par Cell). Voir mon sujet précédent : "Drag & Drop entre DataGridView". Avec le Drag-Drop, je peux passer un DGV.SelectedRows et récupérer un objet de type DataGridViewSelctedRowCollection par l'argument e de l'évènement DragDrop.

Dans mon essai de Copier-Coller, je peux faire le ClipBoard.SetDataObject(DGV.SelectedRows) et je devrais pouvoir récupérer les "Rows" dans un ClipBoard.GetDataObject(...).

Cela ne semble pas évident...

Cordialement,

Sam

0
dysorthographie Messages postés 44 Date d'inscription jeudi 27 janvier 2022 Statut Membre Dernière intervention 4 octobre 2022 4
20 sept. 2022 à 17:56

C'est le contrôle v que tu n'arrives pas à intercepté ?

0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Sam_Placi Messages postés 25 Date d'inscription mercredi 29 juin 2022 Statut Membre Dernière intervention 21 septembre 2022 1
Modifié le 20 sept. 2022 à 19:30

Je pense que c'est là qu'est le problème;  L'erreur  "La référence d'objet n'est pas définie à une instance d'un objet." vient à la ligne "For Each R ... ". 

'... ... ...
                If e.KeyCode = Keys.V Then
                    Dim Selection As IDataObject = Clipboard.GetDataObject()
                    For Each R As DataGridViewRow In Selection.GetData(GetType(DataGridViewSelectedRowCollection))
                        DGV.Rows.Add(R)
                    Next
                End If
'... ... ...
0
vb95 Messages postés 3097 Date d'inscription samedi 11 janvier 2014 Statut Non membre Dernière intervention 6 octobre 2022 158
20 sept. 2022 à 19:31

Bonjour

que vaut Selection à la ligne 3 de ton dernier message et quel est son type de variable ?


0
Sam_Placi Messages postés 25 Date d'inscription mercredi 29 juin 2022 Statut Membre Dernière intervention 21 septembre 2022 1
20 sept. 2022 à 19:56

La variable Selection est déclarée à la ligne précédente. Elle est du type IDataObject (j'ai essayé aussi le type DataObject) et elle est supposée recevoir l'objet qui a été capturé par le ClipBoard.SetDataObject programmé dans le CTRL+C. Il y a une méthode de test de cette variable qui renvoie True ou False selon le cas : Selection.GetDataPresent. Je l'ai testée avant le For, dans un MessageBox : j'obtiens la valeur True. Donc le DataObject n'est ni vide, ni Nothing. Il contient quelque chose que je ne sais pas extraire ...

0
vb95 Messages postés 3097 Date d'inscription samedi 11 janvier 2014 Statut Non membre Dernière intervention 6 octobre 2022 158
20 sept. 2022 à 21:10

J'ai fait un programme de test à partir de la discussion "Drag & Drop entre DataGridView .

Je vais chercher le souci pour la récupération depuis le presse papier


0
Sam_Placi Messages postés 25 Date d'inscription mercredi 29 juin 2022 Statut Membre Dernière intervention 21 septembre 2022 1
20 sept. 2022 à 21:51

Merci d'avance...

Bonne soirée quand même.

Sam

0
Sam_Placi Messages postés 25 Date d'inscription mercredi 29 juin 2022 Statut Membre Dernière intervention 21 septembre 2022 1
21 sept. 2022 à 08:31

Merci pour cette solution.

Elle est très proche de la précédente proposée par dysorthographie mais son implémentation sur mon propre code la rend beaucoup plus lisible et, à défaut de pouvoir récupérer des "Rows" toutes faites, je vais travailler à partir de ce code.

Il me reste à trouver une solution "simple" pour que les Copier-Coller puissent être effectués sur des instances différentes (comme pour "mon" Drag-Drop). C'est pour cela que je comptais sur le Clipboard, me disant qu'étant une fonctionnalité du système, il devait bien pourvoir être lu de n'importe quelle instance, comme je peux coller une sélection d'une XLS dans une autre, ou dans un DOC, ou dans le NotePad.

Encore merci.

Bonne journée,

Sam

0