By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
432,069 Members | 1,716 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 432,069 IT Pros & Developers. It's quick & easy.

How to copy rows from one DataGridView to another?

BRawn
P: 28
Hi guys,

I'm struggling to copy rows from one DataGridView to another. This may sound redundant but it's necessary for my Orders project. I have 3 DataGridViews on one form.

The first DataGridView gets populated from my database with the product and total available stock. The second DataGridView is sort of a basket...so, when an item is selected from the first DataGridView, the item gets added to the second DataGridView and there's an editable column in the second DataGridView in which the user can enter an amount they want of the product in question.

The third one is just for show. It displays the product and the remaining stock quantity (what there was minus the amount entered by the user).

My problem is this: My item adds fine from the 1st DataGridView to the second, but when I add more than one item and edit the quantities, it doesn't subtract from the correct product, so I'm now trying to copy the rows of my 2nd DataGridView to my 3rd one and try in baby steps, but that's not going too well. Here's what I've tried already:

Expand|Select|Wrap|Line Numbers
  1.  
  2. private void copyDGVRows()
  3.         {
  4.             dgvProductsAfterOrders.Rows.Clear();
  5.             for (int i = 0; i <= dgvLineItems.Rows.Count; i++)
  6.             {
  7.                 dgvProductsAfterOrders.Rows[i].Cells[i].Value = dgvLineItems.Rows[i].Cells[i].Value;
  8.                 //dgvProductsAfterOrders.Rows.Add(i + 1);
  9.             }
  10.         }
  11.  
  12.         private void copyDGVRows()
  13.         {
  14.             dgvProductsAfterOrders.Rows.Clear();
  15.             if (dgvLineItems.Rows.Count == 0)
  16.             {
  17.                 return;
  18.             }
  19.             else
  20.             {
  21.                 foreach (DataGridViewRow row in dgvLineItems.Rows)
  22.                 {
  23.                     row.Cells[1].Clone();
  24.                     for (int i = 0; i < row.Cells.Count; i++)
  25.                     {
  26.                         dgvProductsAfterOrders.Rows[i].Cells[1].Value = row;
  27.                         //dgvProductsAfterOrders.Rows.Add(row);
  28.                     }
  29.                 }
  30.             }
  31.         }
  32.  
  33.         private void copyDGVRows(DataGridView dataGridView, ArrayList rowsToCopy)
  34.         {
  35.             for (int i = 0; i < rowsToCopy.Count; i++)
  36.             {
  37.                 DataGridViewRow row = new DataGridViewRow();
  38.                 row = (DataGridViewRow)dataGridView.Rows[Convert.ToInt32(rowsToCopy[i])].Clone();
  39.  
  40.                 for (int j = 0; j < row.Cells.Count; j++)
  41.                 {
  42.                     row.Cells[j].Value = dataGridView.Rows[Convert.ToInt32(rowsToCopy[i])].Cells[j].Value;
  43.                     dataGridView.Rows.Add(row);
  44.                 }
  45.             }
  46.         }
  47.  
  48.         private void populate3rdGrid()
  49.         {
  50.             dgvProductsAfterOrders.Rows.Clear();
  51.             for (int i = 0; i < dgvLineItems.Rows.Count; i++)
  52.             {
  53.                 if (dgvProductsAfterOrders.Rows[i].Cells[0].Value != null)
  54.                 {
  55.                     dgvProductsAfterOrders.Rows.Add();
  56.                     for (int j = 0; j < dgvLineItems.Rows.Count; j++)
  57.                     {
  58.                         dgvProductsAfterOrders.Rows[i].Cells[j].Value = dgvLineItems.Rows[i].Cells[j].Value;
  59.                     }
  60.                 }
  61.             }
  62.         }
  63.  
  64.  
Nothing seems to be working...any ideas?
Oct 20 '10 #1
Share this Question
Share on Google+
2 Replies


Expert 100+
P: 218
Maybe it's better thinking about this from the beginning.

First of all we define what we want:
  • read available products from database
  • put products into basket
  • set/change quantity from products in basket
  • show remaining products (available minus basket)

So we need 3 DGVs, calling them dataGridViewAvailable, dataGridViewBasket, dataGridViewRemaining.

Then we need a Product, so we define a class for it, having a property Name which represents e.g. the product-name.
Expand|Select|Wrap|Line Numbers
  1. public class Product {
  2.   public string Name { get; set; }
  3.  
  4.   public Product(string name) {
  5.     Name = name;
  6.   }
  7.  
  8.   public override string ToString() {
  9.     return Name;
  10.   }
  11. }
  12.  
The next thing we need is a representation of quantities of products, therefore we create another class, having Products and Quantities.
Expand|Select|Wrap|Line Numbers
  1. public class OrderItem {
  2.   public Product Product { get; set; }
  3.   public int Quantity { get; set; }
  4.  
  5.   public OrderItem(Product product, int quantity) {
  6.     Product = product;
  7.     Quantity = quantity;
  8.   }
  9. }
  10.  
After that, we need collections, which hold the available, selected/basket and remaining OrderItems. BindingList<OrderItem> are proper for that.
Expand|Select|Wrap|Line Numbers
  1.     BindingList<OrderItem> _availableProducts = new BindingList<OrderItem>();
  2.     BindingList<OrderItem> _basketProducts = new BindingList<OrderItem>();
  3.     BindingList<OrderItem> _remainingProducts = new BindingList<OrderItem>();
  4.  
To show the contents of this lists to the user, we bind them to the DGVs (at initialization/constructor), using the DataSource-property.
Expand|Select|Wrap|Line Numbers
  1. dataGridViewAvailable.DataSource = _availableProducts;
  2. dataGridViewBasket.DataSource = _basketProducts;
  3. dataGridViewRemaining.DataSource = _remainingProducts;
  4.  
This forces the DataGridView to create a column for each property (of OrderItem), so we have two columns Product and Quantity.

Now it's time to fill our _availableProducts from database-data. I've created a test-method which I call in constructor after data-binding.
Expand|Select|Wrap|Line Numbers
  1. void FillAvailable() {
  2.   //Here the data would come from database
  3.   _availableProducts.Add(new OrderItem(new Product("P1"), 100));
  4.   _availableProducts.Add(new OrderItem(new Product("P2"), 250));
  5. }
  6.  
At this stage it should work that in the first DGV the right values are showing.

When I double-click a cell in my first DGV, I want to add a OrderItem to my second DGV.
Each dgv-row has a corresponding DataBoundItem thich is in our case of type OrderItem.
We take this order-item, extract the product and create a new order-item with that product and a default quantity of zero
which we than add to the basket.
Expand|Select|Wrap|Line Numbers
  1. //designer-created event-handler for CellDoubleClick
  2. void dataGridViewAvailable_CellDoubleClick(object sender, DataGridViewCellEventArgs e) {
  3.   if (e.RowIndex != -1) {
  4.     OrderItem order = dataGridViewAvailable.Rows[e.RowIndex].DataBoundItem as OrderItem;
  5.     _basketProducts.Add(new OrderItem(order.Product, 0));
  6.   }
  7. }
  8.  
Now the whole work is nearly done. Looking back to the list on this thread's beginning, there is just one point missing, namely showing the remaining products.
For this purpose we create an update-method. This method summarizes all basket-orderitem's quantities (per Product) and deduct this sum
from the available product-quantity.
This can be done using some for/foreach loops and temporary lists (to group equal products).
For reasons of lazyness, I used some Linq.
Expand|Select|Wrap|Line Numbers
  1. void UpdateRemaining() {
  2.   _remainingProducts.Clear();
  3.   foreach (var remainingProduct in from order in _basketProducts
  4.                                    group order by order.Product into grp
  5.                                    join availableProduct in _availableProducts on grp.Key equals availableProduct.Product
  6.                                    select new OrderItem(grp.Key, availableProduct.Quantity - grp.Select(o => o.Quantity).Sum()))
  7.     _remainingProducts.Add(remainingProduct);
  8. }
  9.  
The very last thing is to call this update-method when the user changes the amount of products in basket,
simply we can use the CellValueChanged-event of dataGridViewBasket after creating it with the designer.

Expand|Select|Wrap|Line Numbers
  1. private void dataGridViewBasket_CellValueChanged(object sender, DataGridViewCellEventArgs e) {
  2.   UpdateRemaining();
  3. }
  4.  
Now the base-functionality is provided. The next steps would be increase user-friendlyness, stability and so on.
Hope this helps for the beginning :-)
Oct 20 '10 #2

BRawn
P: 28
Thanks Chris. I'm gonna give this a go...tomorrow though coz it's almost hometime for me :)

In the meantime I've devised another way around this to refresh the 3rd DataGridView's data every time the "basket's" amount cells were changed. This is what I did:

Expand|Select|Wrap|Line Numbers
  1.  
  2. private void CalculateAvailableStock()
  3.         {
  4.             DataTable dataTable = new DataTable();
  5.             DataColumn datacolumn1 = new DataColumn("Product Name", typeof(System.String)); // string FirstC=”column1″
  6.             DataColumn datacolumn2 = new DataColumn("Available Quantity (After Order)", typeof(System.String)); // string SecondC=”column2″
  7.             dataTable.Columns.Add(datacolumn1);
  8.             dataTable.Columns.Add(datacolumn2);
  9.  
  10.             foreach (DataGridViewRow lineItemsRow in dgvLineItems.Rows)
  11.             {
  12.                 int total = 0;
  13.                 DataRow dr = dataTable.NewRow();
  14.  
  15.                 foreach (DataGridViewRow productsBeforeOrdersRow in this.dgvProductsBeforeOrders.Rows)
  16.                 {
  17.                     if (lineItemsRow.Cells[1].Value.ToString() == productsBeforeOrdersRow.Cells[1].Value.ToString())
  18.                     {
  19.                         int orderedQuantity = 0;
  20.                         int availableQuantity = 0;
  21.  
  22.                         orderedQuantity = int.Parse(lineItemsRow.Cells[2].Value.ToString());
  23.                         availableQuantity = int.Parse(productsBeforeOrdersRow.Cells[2].Value.ToString());
  24.                         total = availableQuantity - orderedQuantity;
  25.                     }
  26.                 }
  27.                 dataTable.Rows.Add(lineItemsRow.Cells[1].Value.ToString(), total);
  28.             }
  29.             dgvProductsAfterOrders.DataSource = dataTable;
  30.         }
  31.  
  32.  
It's probably not best practices but it works, although I think for practicality I'll give your method a go tomorrow as I like the way you use your objects.

Thanks again :)
Oct 20 '10 #3

Post your reply

Sign in to post your reply or Sign up for a free account.