简体   繁体   中英

Copy selected rows from a DataGridView to another, including Image Column

I'm currently trying to copy selected rows from one DataGridView to another.
I'm trying to capture the value of the CheckBox, where if it's checked, then the entire row will be copied to another DataGridView.

For example, like add to cart then review cart. I've referred to the following post:
Copy selected datagridrow to new datagridview on different form

However it doesn't seem to help.
I've tried using a For loop like the one below, but I'm not entirely sure how to go about this.

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

AppendColumnsToDGV2 :

  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

What I'm doing here isn't working and I have no idea how to go about this.
Any help would be appreciated, thank you, kindly.

Whenever I run this code, I get the error:

System.NullReferenceException: Object reference not set to an instance of an object

I'm not sure how to fix it.

This is what the DataGridView looks like:

什么DGV看起来像

This question is strictly related to the previous one:
Display images in a DataGridView column using JSON objects as DataSource

You're using a sub-class ( Result ) of the RootObject to fill the first DataGridView.

Modify the Result class as follows:

  • Add a new property, Selected As Boolean , decorated with a <JsonIgnore> attribute.
  • Add a new sub-class, called SelectionResult here, a selection of properties of the Result class that you think are needed in the second DataGridView to show the selected products.
  • Add a copy method to the Result class which returns a sub-section of itself as a SelectionResult object.

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
  • Add two List(Of Class) as Fields in the Form. The main class, in the previous question, was called ProductsQuery , so I'm re-using the names already defined there:

Private CurrentProducts As List(Of ProductsQuery.Result) = New List(Of ProductsQuery.Result)()
Private SelectedProducts As List(Of ProductsQuery.SelectionResult) = New List(Of ProductsQuery.SelectionResult)()
  • In the method that fills the first DataGridView, initialize the CurrentProducts List:

     CurrentProducts = New List(Of ProductsQuery.Result)()
  • After the JSON has beed deserialized, fill the List with the JSON results:

     CurrentProducts.AddRange(JsonPost.uk.ghs.Products.Results)

In the event handler of the Button that adds the selected products to the second DataGridView, insert this code:

Edit :
The SelectedProducts list preserves the items selected in the first DataGridView: only the items that are not already in the CurrentProducts list are added to the selection.

The btnRemoveSelection Button removes the selected items in the second DataGridView from the SelectedProducts list. The DataGridView Row selection is somewhat cumbersome, so might want to add a CheckBox Column to ease the selection of the items to remove.

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

This fills the List(Of SelectedProducs) with the selected elements of the first DataGridView and sets the DataSource of the second DataGridView to this List.

Note that the first Column of the DataGridView is set to Visible = False , because that Column corresponds to the ID property of the element selected

The GetSelectionResult() of the Result class returns the properties values that have been defined in the SelectionResult class. You can of course re-define this class to contain whatever properties you see fit.


This is the result of these modifications:

DataGridView JSON 结果

If you are databinding correctly, your underlying data will update when the checkbox is clicked. Then you can just use some LINQ. You should avoid iterating over your DataGridViewRows whenever possible (here it is possible) because they shouldn't hold the data, rather display it.

This simple example works in a form with two DataGridViews and one Button with default names, in 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

在此处输入图片说明

You are currently using 2 separate DataTables. Also you are attempting to add row each time you set a column value. This might work for you.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM