Home > Software design >  How do I add selected cells into a different DataGridView box
How do I add selected cells into a different DataGridView box

Time:02-15

[Move from available to selected on double click][1]

I have to 2 datagridview boxes and I want to move a particular cell that a user has clicked on to the other box

I tried this

private void availableFacilList_CellContentDoubleClick(object sender, DataGridViewCellEventArgs e)
{
    var selectedMove = availableFacilList.Rows[e.RowIndex].Cells[0].Value.ToString();
    DataGridViewRow row = (DataGridViewRow)selectedFacilList.Rows[0].Clone();
    row.Cells[0].Value = selectedMove;
    selectedFacilList.Rows.Add(row);
}

Image attached on how it looks [1]: https://i.stack.imgur.com/qjWiX.png

CodePudding user response:

As noted in the comments, the posted code appears to work if the second grid had at least one column. I am confident this is why the index out of range exception is thrown on the line of code…

DataGridViewRow row = (DataGridViewRow)selectedFacilList.Rows[0].Clone();

Since … selectedFacilList.Rows[0] … row zero (0) does not exist.

Using a DataSource to both grids may make things easier for you. In this case, if both grids used two different DataTables with the same schema, then all you would need to do is move the selected row (s) from one DataTable to the other and the grids will update automatically.

To start, we want to make two (2) data tables with the same schema. It will have a single string column and we will use these tables to move the selected row from one table to the other and vice versa.

Creating these tables and filling one with some test data for the grid on the left may look similar to what your picture shows with the exception that the grid on the right has at least one column.

DataTable AvailableDT;
DataTable SelectedDT;

public Form1() {
  InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e) {
  AvailableDT = GetEmptyDT();
  SelectedDT = GetEmptyDT();
  FillTableWithData(AvailableDT);
  availableFacilGrid.DataSource = AvailableDT;
  selectedFacilGrid.DataSource = SelectedDT;
}

private DataTable GetEmptyDT() {
  DataTable dt = new DataTable();
  dt.Columns.Add("Group", typeof(string));
  return dt;
}

private void FillTableWithData(DataTable dt) {
  dt.Rows.Add("Max Group of Hospitals");
  dt.Rows.Add("Fortis Group of Hospitals");
  dt.Rows.Add("Manipal Group of Hospitals");
  dt.Rows.Add("Appolo Group of Hospitals");
}

Next we need to subscribe to each grid’s CellDoubleClick event to move the rows back and forth. To simplify things, instead of writing code to move the row from the left to right and more code to move the row from right to left… we write one method that can accommodate both moves.

In this method, we will need to know which “Grid” is the “source” grid so we can get the current selected cell from it. From that passed in grid we can get its DataSource DataTable so we can remove the selected row. The only other thing we need is the destination grids data source to add the row to. These two items are passed into the MoveRow method. This should simplify moving the rows either way and may look something like below…

private void MoveRow(DataGridView sourceGrid, DataTable destDT) {
  int sourceRowIndex = sourceGrid.CurrentRow.Index;
  if (sourceRowIndex >= 0 && !sourceGrid.Rows[sourceRowIndex].IsNewRow) {
    DataRowView selectedRow = (DataRowView)sourceGrid.Rows[sourceRowIndex].DataBoundItem;
    destDT.ImportRow(selectedRow.Row);
    ((DataTable)sourceGrid.DataSource).Rows.Remove(selectedRow.Row);
  }
}

The above code is straight forward… first we get the row index of the source grid’s CurrentRow. This is the row we want to move to the destination grid’s data source. Some bounds checking is made in addition to checking if the row is the grids NewRow in which case we do not want to move that row. If the checks are passed, then we grab the row from the grid with the line of code…

DataRowView selectedRow = (DataRowView)sourceGrid.Rows[sourceRowIndex].DataBoundItem;

This will get the row from the grids DataSource. You may note that when the code sets the sourceRowIndex variable with … int sourceRowIndex = sourceGrid.CurrentRow.Index; … this is the row index in relation to the GRID ROWS… and you may be tempted to get the row from the grids DataSource using THAT index with something like…

DataRowView selectedRow = sourceDT.Rows[sourceRowIndex]; 

This may work and it may not work. If the grid is NOT sorted or filtered, then there is a good chance that there IS a one-to-one correspondence to the row index in the gird and the row index in the grids underlying DataTable. However, if the grid is sorted or filtered, then this one-to-one correspondence is lost. In other words, the row at grid row index 3, may not necessarily be at row index 3 in the underlying data sources DataTable.

To ensure we get the “right” row from the grids data source, each grid Row has a DataBoundItem property that will give us the DataRowView of the corresponding DataRow in the DataTable. The code above shows this and it makes it much easier to add and remove that row from the table.

After we have the DataRowView of the source DataTable it is trivial to “import” the row from the sourceDT table to the destination destDT table. Then remove the row from the sourceDT table. Note, you will get an error if you attempt to simply “Add” the row from the source to the destination table. In other words… instead of using the import code like…

 destDT.ImportRow(selectedRow.Row);

We simply added the row like…

destDT.Rows.Add(selectedRow.Row);

The error will complain that you can not add a row to a table that already belongs to another table. Even if you “remove” the row from the source table before trying to add it to the destination table… you will still get the error. I am betting the row is still there but simply marked for deletion.

Fortunately, using the DataTables ImportRow avoids this and helps us “copy” the row. So given the MoveRow method above, it should simplify the code in both grids CellDoubleClick events and may look something like…

private void availableFacilGrid_CellDoubleClick(object sender, DataGridViewCellEventArgs e) {
  MoveRow(availableFacilGrid, SelectedDT);
}

private void selectedFacilGrid_CellDoubleClick(object sender, DataGridViewCellEventArgs e) {
  MoveRow(selectedFacilGrid, AvailableDT);
}

I hope this helps and makes sense.

CodePudding user response:

This is a rough implementation of your problem. Use the code as a base as it contains the basic logic and adapt it to your variables and event handlers. Happy coding!

DataTable DTAvailable, DTSelected;
internal void SetupGrid(Grid _grid, string _columnName)
{ //Add the columns  for the _grid object with the name _columnName}

internal void DoGridsLoad()
{ 
  DTSelected = LoadData();
  SetupGrid(Grid1, "Selected"); 
  Grid1.DataSource = DTAvailable;
  
  SetupGrid(Grid2, "Available");
  DTSelected = new DataTable();
  Grid2.DataSource = DTSelected;

}

internal void MoveToSelected(object sender, EventArgs e) //BTN Move to Selected
{ 
  DataRow toMove = DTAvailable[Grid1.CurrentRowIndex]; //locate Row
  DTSelected.Rows.Add(toMove);
  DTAvailable.Rows.Remove(toMove);
}

internal void MoveToAvailable(object sender, EventArgs e) //BTN Move to Available
{ 
  DataRow toMove = DTSelected[Grid2.CurrentRowIndex]; //locate Row
  DTAvailable.Rows.Add(toMove);
  DTSelected.Rows.Remove(toMove);
}
  • Related