I have a method:
foreach (DataGridViewColumn column in dgvGeoObjectsFirstView.Columns)
{
geoObjectsColumnsCheckedListBoxFirstView.Items.Add(column.HeaderText, column.Visible);
geoObjectsColumnsCheckedListBoxFirstView.ItemCheck += (ss, ee) =>
{
if (geoObjectsColumnsCheckedListBoxFirstView.SelectedItem != "Show")
{
if (geoObjectsColumnsCheckedListBoxFirstView.SelectedItem != null)
{
var selectedItem = geoObjectsColumnsCheckedListBoxFirstView.SelectedItem.ToString();
foreach (DataGridViewColumn column2 in dgvGeoObjectsFirstView.Columns)
{
if (column2.HeaderText == selectedItem.ToString())
{
column2.Visible = ee.NewValue == CheckState.Checked;
}
}
int currentDisplayIndex = 0;
foreach (DataGridViewColumn dataGridViewColumn in dgvGeoObjectsFirstView.Columns)
{
if (dataGridViewColumn.HeaderText == selectedItem)
{
currentDisplayIndex = dataGridViewColumn.Index;
}
}
int futureDisplayIndex = geoObjectsColumnsCheckedListBoxFirstView.SelectedIndex;
PassColumnsInFirstView(futureDisplayIndex, currentDisplayIndex);
}
}
else
{
//What can I do here to have item checked
}
};
}\
The problem is taht one column which header text "Show" shouldn't be uncheckable, so I want something like aborting unchecking for this item.
Maybe some event on checkedlistbox?
Best regards
Make the column read-only and then you needn't fiddle with preventing it from being changed.
Otherwise, subscribe to the CellEndEdit event and set e.Cancel = true.
Related
The following source code is intended to set focus to the immediately previous row of a deleted row.
Suppose I want to delete an unwanted word dddddddd from the database. When I press the Delete button, I want the word cynosure to be focused and placed at the top of the DataGridView which is not the case right now.
Right now, it is displayed at the bottom.
Source Code
void SetFocusToWord(Word concernedWord)
{
if (concernedWord != null)
{
int index = 0;
foreach (DataGridViewRow r in dataGridView1.Rows)
{
Word item = r.Tag as Word;
if (concernedWord.Name == item.Name)
{
dataGridView1.Focus();
dataGridView1.CurrentCell = dataGridView1.Rows[index].Cells[0];
break;
}
index++;
}
}
}
private void btnDelete_Click(object sender, EventArgs e)
{
try
{
if (dataGridView1.SelectedRows.Count > 0)
{
int selectionIndex = dataGridView1.SelectedRows[0].Index;
foreach (DataGridViewRow r in dataGridView1.SelectedRows)
{
Word c = r.Tag as Word;
if (c != null)
{
_wordDatabase.Delete(c);
}
}
LoadToDataGridView();
if(selectionIndex > 0)
{
selectionIndex = selectionIndex - 1;
}
Word item = dataGridView1.Rows[selectionIndex].Tag as Word;
SetFocusToWord(item);
}
else
{
throw new Exception(SelectionErrorMessages.GetErrorMessageFor(typeof(Word)));
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
void LoadToDataGridView()
{
dataGridView1.Rows.Clear();
List<Word> items = (List<Word>)_wordDatabase.Get();
if (items != null)
{
if (items.Count > 0)
{
int i = 0;
foreach (Word c in items)
{
dataGridView1.Rows.Add(c.Name, c.Hint);
dataGridView1.Rows[i].Tag = c;
++i;
}
}
}
}
Reloading the database seems like an unnecessary step.
Based on how you want the grid to behave, try using code like this:
if (dataGridView1.SelectedRows.Count > 0) {
int selectIndex = dataGridView1.SelectedRows[0].Index;
dataGridView1.Rows.RemoveAt(selectIndex);
if (selectIndex > 0) {
dataGridView1.ClearSelection();
dataGridView1.Rows[selectIndex - 1].Selected = true;
dataGridView1.FirstDisplayedScrollingRowIndex = selectIndex - 1;
}
}
Poor performance and abundance of unnecessary code in your project are the result of you not using winforms binding properly. I suggest you start utilizing control's BindingContext and BindingSource accordingly. This should solve most of your problems.
For further details on winforms binding I recommend this docs.
Can please any one help me on this. I have developed a c# windows application which has DataGridView first column has checkboxes. if I click on first column header it selects all the row level check boxes except the first row. For selecting all row level check boxes I have an event of dataGridView1_ColumnHeaderMouseClick and the code is:
private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
foreach (DataGridViewColumn column in dataGridView1.Columns)
{
column.SortMode = DataGridViewColumnSortMode.NotSortable;
}
if (e.ColumnIndex == 0)
{
if (chek == 0)
{
try
{
for (int i = 0; i < dataGridView1.RowCount; i++)
{
string paymentValue = dataGridView1.Rows[i].Cells[18].Value.ToString();
string incmngp = dataGridView1.Rows[i].Cells[20].Value.ToString();
if (paymentValue == "N" && incmngp =="")
{
dataGridView1.Rows[i].Cells[0].Value = 1;
chek = 1;
}
}
if (chek == 1)
{
btn_update.Text = "Update";
}
}
catch (Exception ) { }
}
else if(chek==1)
{
try
{
for (int i = 0; i < dataGridView1.RowCount; i++)
{
dataGridView1.Rows[i].Cells[0].Value = 0;
chek = 0;
}
if (chek == 0)
{
btn_update.Text = "OK";
}
}
catch (Exception) { }
}
}
Note: chek is the variable declared on initialize stage
Set your Selection mode property of data grid view to ColumnHeaderSelect
and make sure all your 'Text' columns have SortMode set to NotSortable
UPDATE 2
In which case, Undo everything I ever told before and do that like this
Before you are assigning any DataTable to dataGridView1.
da.Fill(dt);
dataGridView1.DataSource = dt.DefaultView;
dataGridView1.SelectionMode = DataGridViewSelectionMode.RowHeaderSelect;
foreach(DataGridViewColumn dc in dataGridView1.Columns)
{
dc.SortMode = DataGridViewColumnSortMode.NotSortable;
}
dataGridView1.SelectionMode = DataGridViewSelectionMode.ColumnHeaderSelect;
UPDATE 3
Add an event handler for your dataGridView1's ColumnHeaderMouseClick Event
like below
Add the below code (Generic code if you want to use the same functionality for any column of check boxes)
private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
//Enter your own column index here
if(e.ColumnIndex == 0)
foreach(DataGridViewRow row in dataGridView1.Rows)
foreach (DataGridViewCell cell in row.Cells)
{
//Check if the cell type is of a CheckBoxCell
if (cell.GetType() == typeof(DataGridViewCheckBoxCell))
{
DataGridViewCheckBoxCell c = (DataGridViewCheckBoxCell)cell;
c.TrueValue = "T";
c.FalseValue = "F";
if (c.Value == c.FalseValue|| c.Value == null )
c.Value = c.TrueValue;
else
c.Value = c.FalseValue;
}
}
dataGridView1.RefreshEdit();
}
This is a very bizarre bug in Winforms. The problem more generally applies not to the first row, but to the first selected cell in any row of DataGridViewCheckBoxCell(s). You can select the CheckBox cell by clicking on the check box, or select the cell outside the check box, the behavior is the same. If you select 3 check boxes in the middle of your grid, the first of those three will freeze and not update properly. If you try to clear the selection in code, with a dataGridView1.ClearSelection() method call, it still does not work.
The correct answer is to call datagridview1.RefreshEdit() right after you change the checkbox data. You can't just call it after all changes are made. It must be made for each change in the CheckBox value.
foreach (DataGridViewRow row in Results.Rows)
{
var ck = (DataGridViewCheckBoxCell) row.Cells["check"];
ck.Value = ck.TrueValue;
Results.RefreshEdit();
}
I have a datagridview and a checkbox column attached to it. If the user checks a few rows and then presses a button, I would like to be able to get a certain cell value from each row where the box was ticked.
Something maybe like this:
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (Convert.ToBoolean(row.Cells[CheckBoxColumn1.Name].Value) == true)
{
//...
}
}
The problem is that the datagridview might contain up to 3000 or 4000 rows. I would like to see if there is a faster way to get the checked rows, other than to iterate through all the rows for the grid.
If you don't want to iterate all rows, then use temporary list of checked rows.
Then after button was clicked use values from that List
HashSet<DataGridViewRow> _CheckedRows = new HashSet<DataGridViewRow>();
private void DataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
if (DataGridView.Columns[e.ColumnIndex].Name.Equals(CheckBoxColumn1.Name) == false)
return;
DataGridViewRow row = DataGridView.Rows[e.RowIndex];
if (Convert.ToBoolean(row.Cells[CheckBoxColumn1.Name].Value) == true)
{
_CheckedRows.Add(row);
}
else
{
_CheckedRows.Remove(row);
}
}
You could manage your own list of checked rows.
You would bind to the dataGridView1.CellClick event, and add/remove rows from the list:
var checkedRows = new List<DataGridViewRow>();
dataGridView1.CellClick += (sender, args) =>
{
if (args.RowIndex != YOUR_CHECKBOX_COLUMN_INDEX)
{
return;
}
var cell = dataGridView1[args.ColumnIndex, args.RowIndex];
if (cell.Value == null)
{
cell.Value = false;
}
cell.Value = !(bool)cell.Value;
if ((bool)cell.Value)
{
checkedRows.Add(dataGridView1.Rows[args.RowIndex]);
}
else
{
checkedRows.Remove(dataGridView1.Rows[args.RowIndex]);
}
};
All you have to do then is:
foreach (DataGridViewRow row in checkedRows)
{
//...
}
You can use Linq like this :
var checkedRows = from DataGridViewRow r in dataGridView1.Rows
where Convert.ToBoolean(r.Cells[CheckBoxColumn1.Name].Value) == true
select r;
foreach (var row in checkedRows)
{
//
}
Using CheckBoxColumn1.Name instead of CheckBoxColumn1.Index seems like a tiny bottleneck to me.
To avoid the casting to DataGridViewRow and Boolean, my suggestion is something like (not tested):
int colIndex = CheckBoxColumn1.Index; // or dataGridView1.Columns.IndexOf(CheckBoxColumn1.Name) ?
for ( int r = 0; r < dataGridView1.RowCount; r++ )
{
if ( true.Equals( dataGridView1[colIndex, r].Value ) )
{
//...
}
}
The other answers that use cell events are better because the list of checked rows will be ready when needed, but also can be a bit harder to maintain/debug depending on how you do the filtering and rest. Here is my version:
private HashSet<int> checkedRowIndexes = new HashSet<int>();
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if ( e.ColumnIndex == CheckBoxColumn1.Index )
{
if ( true.Equals( dataGridView1[CheckBoxColumn1.Index, e.RowIndex].Value ) )
checkedRowIndexes.Add(e.RowIndex);
else
checkedRowIndexes.Remove(e.RowIndex);
}
}
My requirement : In datagridview I need select row by clicking the row header and selected row should maintain until I will click the other row header also same time I should select cell too.
My Problem : I can't select multiple row using Shift and Ctrl key.
my code :
List< DataGridViewRow> selectedRows = new List< DataGridViewRow>();
void selectRows()
{
dataGridView1.SuspendLayout();
foreach (DataGridViewRow r in dataGridView1.Rows)
{
r.Selected = selectedRows.Contains(r);
}
dataGridView1.ResumeLayout();
}
private void dataGridView1_RowHeaderMouseClick(object sender,DataGridViewCellMouseEventArgs e)
{
DataGridViewRow clickedRow = dataGridView1.CurrentRow;
if (selectedRows.Contains(clickedRow))
{
selectedRows.Remove(clickedRow);
}
else
{
selectedRows.Add(clickedRow);
}
selectRows();
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if ((row.Index != e.RowIndex) && !row.Selected)
{
row.DefaultCellStyle.BackColor = Color.White;
}
else
{
selectedRows.Remove(clickedRow);
row.Selected = true;
row.DefaultCellStyle.BackColor = Color.Blue;
}
}
}
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.DefaultCellStyle.BackColor == Color.Blue)
{
row.Selected = true;
}
}
}
You have to set your enable your datagridview's multiselect dataGridView.MultiSelect = true;
Be familiar with using a debugger, you will be able to find out where the issue is.
You are clearing the selection in your loop
foreach (DataGridViewRow row in dataGridView1.Rows)
{
}
Rethink the if-else logic in it and you will see why. You are clearing your previous selections when you are not suppose to.
I have a method which select rows in datagrid and change value of checkboxcolumn:
foreach (DataGridViewRow gridRow in dataGridView1.Rows)
{
if (_selectedIDs != null)
foreach (long id in _selectedIDs)
{
gridRow.Selected = false;
if ((long)((DataRowView)gridRow.DataBoundItem)["ObjectD"] == id)
gridRow.Selected = true;
}
if (_checkedIDs != null)
foreach (long id in _checkedIDs)
{
((DataRowView)gridRow.DataBoundItem)["Choosen"] = 0;
if ((long)((DataRowView)gridRow.DataBoundItem)["ObjectD"] == id)
((DataRowView)gridRow.DataBoundItem)["Choosen"]=true;
}
}
dataGridView1.Refresh();
When I'm debugging this code I see that it enters in lines
gridRow.Selected = true;
and
((DataRowView)gridRow.DataBoundItem)["Choosen"]=true;
and in quickwatch I see that properties of those rows are changed.
But after execution of this code I still have only one row selected
Does anyone have an idea what's wrong with this code?
In addition to the MultiSelect, you might want to make sure that the class you databind implements the INotifyPropertyChanged interface.
You also could set the selected = false before you start looping, or you will overwrite your selection every time...
foreach (DataGridViewRow gridRow in dataGridView1.Rows)
{
if (_selectedIDs != null)
// *****
gridRow.Selected = false;
// *****
foreach (long id in _selectedIDs)
{
if ((long)((DataRowView)gridRow.DataBoundItem)["ObjectD"] == id)
gridRow.Selected = true;
}
if (_checkedIDs != null)
foreach (long id in _checkedIDs)
{
((DataRowView)gridRow.DataBoundItem)["Choosen"] = 0;
if ((long)((DataRowView)gridRow.DataBoundItem)["ObjectD"] == id)
((DataRowView)gridRow.DataBoundItem)["Choosen"]=true;
}
}
Make sure the DataGridView.MultiSelect property is set to true.
Today, I have this error and have been fixed by set Enabled to true
dataGridView1.Enabled = true;