[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);
}