I added datagridview to my win forms app and I also added one CheckBox for marking rows.
The CheckBox works as I expected until the user sorts the DataGridView. After the sort the previous selection of checkbox column is lost.
Is there a way I can make my datagridview remember which row is selected after sorting?
You have two options to solve this issue.
The first and possibly the most simple is to bind your checkbox column to your datasource. For example, if you are using a DataTable as your datasource, adding a boolean column will create a checkbox on your DataGridView that will sort and not lose the checked state.
If this is not an option then the other way of addressing the problem is to set your DataGridView to Virtual mode and maintain a cache of your checkbox values.
Check out the excellent DataGridView FAQ for an example of how to do this. I've also provided the code below but do check out the FAQ:
private System.Collections.Generic.Dictionary<int, bool> checkState;
private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.AutoGenerateColumns = false;
dataGridView1.DataSource = customerOrdersBindingSource;
// The check box column will be virtual.
dataGridView1.VirtualMode = true;
dataGridView1.Columns.Insert(0, new DataGridViewCheckBoxColumn());
// Initialize the dictionary that contains the boolean check state.
checkState = new Dictionary<int, bool>();
}
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
// Update the status bar when the cell value changes.
if (e.ColumnIndex == 0 && e.RowIndex != -1)
{
// Get the orderID from the OrderID column.
int orderID = (int)dataGridView1.Rows[e.RowIndex].Cells["OrderID"].Value;
checkState[orderID] = (bool)dataGridView1.Rows[e.RowIndex].Cells[0].Value;
}
}
private void dataGridView1_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
// Handle the notification that the value for a cell in the virtual column
// is needed. Get the value from the dictionary if the key exists.
if (e.ColumnIndex == 0)
{
int orderID = (int)dataGridView1.Rows[e.RowIndex].Cells["OrderID"].Value;
if (checkState.ContainsKey(orderID))
e.Value = checkState[orderID];
else
e.Value = false;
}
}
private void dataGridView1_CellValuePushed(object sender, DataGridViewCellValueEventArgs e)
{
// Handle the notification that the value for a cell in the virtual column
// needs to be pushed back to the dictionary.
if (e.ColumnIndex == 0)
{
// Get the orderID from the OrderID column.
int orderID = (int)dataGridView1.Rows[e.RowIndex].Cells["OrderID"].Value;
// Add or update the checked value to the dictionary depending on if the
// key (orderID) already exists.
if (!checkState.ContainsKey(orderID))
{
checkState.Add(orderID, (bool)e.Value);
}
else
checkState[orderID] = (bool)e.Value;
}
}
I'm surprised that that happens, but if there's no other way around it in a worst case you could set the sorting to programmatic and then handle when the user clicks on the column header, save a list of which items are checked, do the sorting programmatically and then check any items that should be checked.
Related
I have a DataGridView with a column of comboboxes. These comboboxes can hold a number between 1-24. I have 8 rows in the the DGV and I want to prevent any two rows from having the same number selected in the combobox. If the CB that changed conflicts with any other CB I set the one that changed back to the previous value stored in "CorrectSlotSelections". If the change is valid and has no conflicts I update the value stored in "CorrectSlotSelections".
This all works properly, however the value displayed on screen does not update if it was found to be invalid, even though I overwrite the incorrect value. Upon inspection of the DGV in debug mode I can see that I have poperly overwritten the value, but the property "EditedFormattedValue" does still show the old, incorrect, value. How can I change this to update the UI so it shows the corrected value?
// This event handler manually raises the CellValueChanged event
// by calling the CommitEdit method.
void dataGridView1_CurrentCellDirtyStateChanged(object sender,
EventArgs e)
{
if (this.ChannelConfigDataGridView.IsCurrentCellDirty)
{
// This fires the cell value changed handler below
ChannelConfigDataGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
private void ChannelConfigDataGridView_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
DataGridViewComboBoxCell cb = (DataGridViewComboBoxCell)ChannelConfigDataGridView.Rows[e.RowIndex].Cells[2];
if (cb.Value != null)
{
// Check all rows for a cell in column 3 that has the value that was just changed.
List<DataGridViewRow> rowsWithDuplicateValue = ChannelConfigDataGridView.Rows.Cast<DataGridViewRow>().Where(x => (int)x.Cells[2].Value == (int)cb.Value).ToList();
if (rowsWithDuplicateValue == null || rowsWithDuplicateValue.Count() == 0)
{
return;
}
// If more than one item with this value was found we must handle the duplicates.
if (rowsWithDuplicateValue.Count() > 1)
{
ChannelConfigDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = CorrectSlotSelections[e.RowIndex];
}
// If only one was found update the correct slot selections.
else if(rowsWithDuplicateValue.Count() == 1)
{
CorrectSlotSelections[e.RowIndex] = (int)cb.Value;
}
ChannelConfigDataGridView.Invalidate();
}
}
i have a Datagridview that contains columns.
when i click on the item on the column.
it always select the first row
i also tried
.currentcell = null and .clearselection();
// i inserted this one on the form_load
but nothing happens.
here is my code
private void dgv1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 0)
{
dgv1.CurrentCell = null;
dgv1[e.ColumnIndex, e.RowIndex].Value.ToString();
if (Path.GetExtension(path) == ".pdf")
{
Process.Start(path);
}
}
}
What do you want the user to select in the first place?
There is a property for selectionmode in datagridview.
Change it to CellSelect if you want it to select cells only.
Alternatively, use dataGridView.SelectionMode = DataGridViewSelectionMode.CellSelect;
After reading what you said on the comment, from that I infer that you are trying to click a cell and read the cell from your program?
If so, you could try
dataGridView[e.ColumnIndex, e.RowIndex].Value.ToString();
on the CellContentClick and/or CellClick event
I Have a datagridview that gets data from database and shows to the user,I also have three textboxes through which user can enter the value into the datagrid view if I select an already existing row in the datgrid and then enter value by text boxes it makes the changes and when I push change button changes are made successfully in both db and the datagridview
but if I select an empty row in the datagrid view and try to enter the values I cannot new row is not added to the datagrid view although allow user to add new row is set to true.
private void txtName_TextChanged(object sender, EventArgs e)
{
if (dataGridView1.SelectedRows.Count == 1)
{
dataGridView1.SelectedRows[0].Cells["Name"].Value = txtName.Text;
}
}
private void txtRelation_TextChanged(object sender, EventArgs e)
{
if (dataGridView1.SelectedRows.Count == 1)
{
dataGridView1.SelectedRows[0].Cells["Relation"].Value = txtRelation.Text;
}
}
private void txtID_TextChanged(object sender, EventArgs e)
{
if (dataGridView1.SelectedRows.Count == 1)
{
dataGridView1.SelectedRows[0].Cells["ID"].Value = txtID.Text;
}
}
Check if your gridview is readonly. If Readonly is true then set it to false to enable user add new row. Another reason might be the "EditMode" property of DataGridView. It should not be "Edit Programatically" if you want to allow user to add new row
You have to double click a row to actually create a new row. However, if you do not want the stress of double clicking, you could make the row select event to perform a click on the row.
I have a datagridview with multiple checkboxes. When the Finished checkbox is checked I need to execute linq code to update a specific table. How do I find out if that specific check box is dirty and where do I write the code to pass the values I need to be passed to the table. Note that it is not the same table that the datagridview is based on.
Thanks.
EDIT:
private void propertyInformationDataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
DataGridViewCheckBoxCell checkCell = (DataGridViewCheckBoxCell)propertyInformationDataGridView.Rows[e.RowIndex].Cells[3];
DataGridViewRow row = propertyInformationDataGridView.Rows[e.RowIndex] as DataGridViewRow;
System.Data.DataRowView SelectedRowView;
newCityCollectionDataSet.PropertyInformationRow SelectedRow;
SelectedRowView = (System.Data.DataRowView)propertyInformationBindingSource.Current;
SelectedRow = (newCityCollectionDataSet.PropertyInformationRow)SelectedRowView.Row;
if (Convert.ToBoolean(checkCell.EditedFormattedValue) == true)
{
DataClasses1DataContext dc = new DataClasses1DataContext();
var matchedCaseNumber = (from c in dc.GetTable<PropertyInformation>()
where c.CaseNumberKey == SelectedRow.CaseNumberKey
select c).SingleOrDefault();
reportsSent newReport = new reportsSent();
newReport.CaseNumberKey = SelectedRow.CaseNumberKey;
dc.reportsSents.InsertOnSubmit(newReport);
dc.SubmitChanges();
}
}
Do I need to endedit at some point is that the issue?
This is from some of my code, all you need to do is create a "CellContentClick" event for your datagridview.
The easiest way to do this is select the Datagridview, go to properties and click on the lightning bolt. Scroll down to "CellContentClick" and double click in the empty box. This will auto generate the method you need to paste the following code into.
Make sure you rename my instances of "CustomersDataGridView" to whatever yours is named as well, intellisense should highlight invalid code in red that you need to replace.
Also, the "9" you see in the checkCell declaration needs to be changed to the index of your "Finished" check-box. If it is in the 3rd cell from the left, put a 2 there instead of a 9, as the indexing is 0 based.
EDITTED to fix comments:
private void CustomersDataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex.ToString() == "9")
{
DataGridViewCheckBoxCell checkCell = (DataGridViewCheckBoxCell)CustomersDataGridView.Rows[e.RowIndex].Cells[9];
DataGridViewRow row = CustomersDataGridView.Rows[e.RowIndex] as DataGridViewRow;
if (Convert.ToBoolean(checkCell.EditedFormattedValue) && CustomersDataGridView.IsCurrentCellDirty)
{
//Do Work here.
var z = row.Cells[0].Value; // Fill in the brackets with the column you want to fetch values from
//z in this case would be the value of whatever was in the first cell in the row of the checkbox I clicked
}
}
}
You can do it in the CheckedChanged-Event
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
// Do what you have to do...
}
I have a datagrid with 2 columns. One is a checkbox and one is a normal textbox cell. All is bound to one BindingList which is an entity.
If I check one checkbox and then loop to get the checked entities from the BindingList, it returns nothing. But if I check then edit the textbox column, it works just fine and return one result.
I tried to refresh or to check then click somewhere else. It doesn't work.
How do you manage to get your bindingList updated when you check a column?
Thank you!
What data type is the column in the data source (dataTable)? Is it boolean type?
But this doesnt matter so much, what matters is that you use the correct event of the dgv.
Use:
1. CurrentCellDirtyStateChanged and
2. CellValueChanged
This is the code you have to use:
private void CreateAndBind()
{
DataTable table = GetDataToDataTable();
//then bind it to dgv:
dgv.DataSource = new BindingSource(table, null);
//create events for dgv:
dgv.CurrentCellDirtyStateChanged += new EventHandler(dgv_CurrentCellDirtyStateChanged);
dgv.CellValueChanged += new EventHandler(dgv_CellValueChanged);
}
private DataTable GetDataToDataTable()
{
//get data from dataBase, or what ever...
table.Columns.Add("column1", typeof(stirng));
table.Columns.Add("column2", typeof(bool));
//adding some exmaple rows:
table.Rows.Add("item 1", true);
table.Rows.Add("item 2", false);
return table;
}
void dgv_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (dataGridView1.IsCurrentCellDirty)
dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
private void dgv_CellValueChanged(object obj, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 0) //compare to checkBox column index
{
DataGridViewCheckBoxCell check = dataGridView1[0, e.RowIndex] as DataGridViewCheckBoxCell;
if (Convert.ToBoolean(check.Value) == true)
{
//If tick is added!
//
}
}
}
Hope it helps.