I have a DataGridView with a list<> (global variable) as datasource, the list is a list of a self made user data type.
The first value in the UDT is a boolean so it shows a checkbox in the DataGridView.
When I check/uncheck a checkbox the boolean value choud be changed in the list<>.
It works with the following code, but it loops through every row and checks the checkbox
private void dgvObjecten_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
for (int i = 0; i < dgvObjecten.Rows.Count; i++)
{
Dig1Objecten[i].Import = (bool)dgvObjecten.Rows[i].Cells["Import"].Value;
}
//refresh DataGridView
dgvObjecten.DataSource = Dig1Objecten;
}
Is there a way to get the row number of the checkbox that gets changed so it doesn't have to loop through all rows every time 1 checkbox is changed?
In WinForms the typical event handler will have a sender object (the Control, Form, or other that sent the event) and an EventArgs structure of various types that provide the contextual information for the event. In this case, the RowIndex and the ColumnIndex can be determined by inspecting the e argument (easy as 𝜋).
Related
First of all what i have:
I got a datagridview and bindsource (currently my own datatable from an sql-call). The bindsource has multiple columns, but one is a specific "position" column for my data.
What i want to do:
When i set the bindsource to the datagridview i want to change the color of a row with a specified "position".
What i did:
I thought it would be enough to create a RowsAdded event and within check if the "position"-column of the added rows equals my specified position. Based on that i would have changed the Backcolor of the row.
The code would be this:
private void setBindSource(BindingSource bindSource)
{
gridview.DataSource = bindSource;
gridview.EndEdit();
bindSource.EndEdit();
}
private void gridView_RowsAdded(object sender, System.Windows.Forms.DataGridViewRowsAddedEventArgs e)
{
if (e.RowIndex == -1 || e.RowCount == 0)
{
return;
}
for (int index = e.RowIndex; index <= e.RowIndex + e.RowCount - 1; index++)
{
DataGridView dgv = sender as DataGridView;
DataGridViewRow row = dgv.Rows[index];
if ((Int32)row.Cells["position"].Value == specificPosition)
row.DefaultCellStyle.BackColor = Color.Green;
}
}
The problem i'm facing:
The rowsadded event fires as expected (at the gridview.DataSource = bindSource;). But the row itself does not have any data in it (the used datatable shows the expected data). So it obviously throws the error, that it can't find the specified column "position". I'm assuming that the gridview isn't fully initialized yet?
How would i be able to change the color of the row when it is added?
When a row’s back ground color depends on a specific cells value, there are a few things you should keep in mind when “changing” the rows color.
“Where” the code is located to test the specific cell value and change the row’s color can be done in many different grid events and all will (basically) accomplish the same thing. However, it may be beneficial to do some simple tests to help you determine if the “grid event” you choose is “REALLY” the one you need or should use.
Example, as suggested, you can subscribe to the grids CellFormatting event to do what you describe and it will work as expected. However, there is a subtle yet possible problematic issue(s) that using this event creates. For starters, just about all the grid “formatting” events will fire many many times.
If the user simply moves the cursor over the grid, then, the formatting event will fire. Therefore, if the cursor just so happens to move over the target cell, the code is executed. This may be acceptable; however, it is clear from this that checking the cells value is really unnecessary since the cells value has not changed. The user simply moved the cursor over the target cell.
As previously stated, this MAY be acceptable, however, if this same unnecessary calling of an event is compounded, it is not difficult to see where many combinations of this situation could impact the UI’s performance and the user may experience a sluggish UI.
The main idea here… is to NOT place your code in an event where the event will get fired unnecessarily, and this is a good example. It may work, but the code is “creating” extra and unnecessary execution steps.
Given this, your attempt to wire up the grids RowsAdded event may well work. However, as you noted, there seems to be a need to do something different when the data is “initially” loaded and when the user manually adds a new row or when the code adds new rows. When the data is “initially” loaded, you are correct that some cells may not yet be initialized. At least the cell your code is looking at.
This can be fixed, however, using the RowsAdded event leaves out one other senario…
_“what if the user CHANGES a cells value of a ‘’position’’ cell?”
The new rows event is not going to fire in that scenario. If the user changes a “position” cell to the value of the specifiedPosition, then, that row’s background color will not get changed.
Given all this, to help, it is best to pin point “WHEN” we want the code to run. And from what I can see, this would be “WHEN” the value in a cell that is in the position column changes. Therefore, I suggest you subscribe to the grids CellValueChanged event. If the cell that “changed” is a “position” cell, then test the cells value and color the row accordingly.
This will minimize the number of calls to the code unnecessarily and will fix the previously described problem when the user “changes” a cells value. This will also work when the “user” adds a new row. Unfortunately, this event will not fire when the data is initially loaded OR when new rows are added through code.
Given this, one possible solution to color the rows after the grid has been initially loaded with data in addition to setting the proper row color for newly added rows in code, a couple of small methods may come in handy.
The first method would simply color one (1) given row depending on what value the ‘position” cell has. This assumes the given row is not null and the position column exists and it is a valid int.
private void ColorRow(DataGridViewRow row) {
if ((int)row.Cells["position"].Value == specificPosition) {
row.DefaultCellStyle.BackColor = Color.LightGreen;
}
else {
row.DefaultCellStyle.BackColor = Color.White;
}
}
We can use the ColorRow method in the grids CellValueChanged event to color that specific row. In addition, in the forms load event, after the data has be initially set into the grid, then we can call an additional method that simply loops through all the grid’s rows and calls the ColorRow method above. This ColorSpecificRows method may look something like…
private void ColorSpecificRows() {
foreach (DataGridViewRow row in gridView.Rows) {
if (!row.IsNewRow) {
ColorRow(row);
}
}
}
Next, all that is left is to subscribe to the grids CellValueChanged event and it may look something like…
private void gridView_CellValueChanged(object sender, DataGridViewCellEventArgs e) {
ColorRow(gridView.Rows[e.RowIndex]);
}
To help test this a complete example is below. Create a new win form solution, add a DataGridView and a Button to the form. The button is used to demonstrate adding rows programmatically.
DataTable GridTable;
BindingSource GridBS;
Random rand = new Random();
int specificPosition = 2;
int formattingCount = 0;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
GridTable = GetTable();
FillTable(GridTable);
GridBS = new BindingSource(GridTable, null);
gridView.DataSource = GridBS;
ColorSpecificRows();
}
private DataTable GetTable() {
DataTable dt = new DataTable();
dt.Columns.Add("Col0", typeof(string));
dt.Columns.Add("position", typeof(int));
dt.Columns.Add("Col2", typeof(string));
return dt;
}
private void FillTable(DataTable dt) {
for (int i = 0; i < 10; i++) {
dt.Rows.Add("C0R" + i, rand.Next(1, 4), "C2R" + i);
}
}
private void button1_Click(object sender, EventArgs e) {
GridTable.Rows.Add("new0", 2, "new0");
GridTable.Rows.Add("new1", 3, "new0");
GridTable.Rows.Add("new2", 2, "new0");
ColorSpecificRows();
}
Lastly, for testing purposes, you can wire up the grids CellFormatting event to demonstrate how often this even is called.
private void gridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) {
Debug.WriteLine("CellFormatting - Enter -- FormattingCount: " + ++formattingCount);
// code to change row color
Debug.WriteLine("CellFormatting - Leave");
}
I hope this makes sense.
How to get the index of last checkbox where checked change from list of them? If someone asks, no, I can't use CheckedListBox control for this project.
I have
List<CheckBox> checkboxes = new List<CheckBox>();
and then I adding some checkboxes to this list
What I want to do is to get the index of checkbox which recently checked state changed
so...
every checkbox from this list have this same handler for the CheckedChanged event
and then in this void I want to get index of this checkbox which trigger this event for example for this code
public void checked_change(object sender, EventArgs e)
{
int x = // here i want this index
if (checkboxes[x].Checked==true)
{
}
}
The object sender argument to the event-handler contains the 'recently changed' CheckBox.
You would need to cast the object back to the CheckBox type and find it's index in the list using List.IndexOf.
int x = checkboxes.IndexOf((CheckBox)sender);
Make sure you only hook CheckBoxes onto the event-handler or perform a safe conversion
My motive is to display some information as link and on click of that, I should be able to get id of clicked item and open new window with detailed information of item. As i am new in win forms but i did some research, Possible option for this might be DataGridViewLinkColumn but i am not able to link id with column data and click event on which open new window.
Or there any other better approach possible.?
When you have a datagridview you can get the values of a cell as follows:
Firstly, create a cellclick event
datagridview1.CellClick+= CellClickEvent;
DataGridViewCellEventArgs holds some properties, these would be rowindex (row you clicked) and columnindex (column you clicked) and some other...
make a datagrid with 2 columns, column 0 holds the Id of the row, column 1 holds the link
void CellClickEvent(object sender, DataGridViewCellEventArgs e)
{
if(e.ColumnIndex == 1) // i'll take column 1 as a link
{
var link = datagridview1[e.columnindex, e.rowindex].Value;
var id = datagridview1[0, e.rowindex].Value;
DoSomeThingWithLink(link, id);
}
}
void DoSomeThingWithLink(string link, int id)
{
var myDialog = new Dialog(link,id);
myDialog.ShowDialog();
myDialog.Dispose(); //Dispose object after you have used it
}
I'm assuming you're using a DataGridView element.
What you could do is use the CellClick event of the object. It will have a DataGridViewCellEventArgs object passed on, on which there's a ColumnIndex property and a RowIndex property. This way you could figure out where in the the datagrid the user clicked.
And, for example, you could use that information to look up the id or other info since you now know the row & the cell the user clicked on.
arbitrary e.g.:
// wire up the event handler, this could be anywhere in your code
dataGridView.CellClick += dataGridView_CellClick; // when the event fires, the method dataGridView_CellClick (as shown below) will be executed
private void dataGridView_CellClick(object sender, DataGridViewCellEventArgs e)
{
var rowIndex = e.RowIndex;
var columnIndex = e.ColumnIndex; // = the cell the user clicked in
// For example, fetching data from another cell
var cell = dataGridView.Rows[rowIndex].Cells[columnIndex];
// Depending on the cell's type* (see a list of them here: http://msdn.microsoft.com/en-us/library/bxt3k60s(v=vs.80).ASPX) you could cast it
var castedCell = cell as DataGridViewTextBoxColumn;
// Use the cell to perform action
someActionMethod(castedCell.Property);
}
(*DataGridViewCell types: http://msdn.microsoft.com/en-us/library/bxt3k60s(v=vs.80).ASPX)
I am using a Datagridview control on winform and a bindingsource for data. Data is filled in bindingsource and accordingly datagridview is populated. I am looking for an event or something like that which will fire up when a row from bindingsource is added to the datagridview.
I want to perform some operations over the added row. I tried with RowsAdded event but e.RowIndex is not being retrieved properly.
Edit1: Let's say I am having 10 records in database table. I am fetching these into bindingsource and using bindingsource as a datasource for Datagridview. Now while adding row to Datagridview, I want to perform some UI operations on the Datagridview. I used RowsAdded event but it is giving me RowIndex as 0 or 1 always. I also tried a foreach loop over RowsCount, and if I debug the code, the execution flow is as per the expectations, but on the UI it is not getting reflected. I have called Datagridview1.refresh() after everything is done.
Can you please help me out to get this ?
When the user adds a new row using the row for new records, the DataGridViewRowsAddedEventArgs.RowIndex value in the handler for this event is equal to the index of the new location of the row for new records, which is one greater than the row just added.
When you add rows programmatically, however, the RowIndex value is the
index of the first row added.
private void dataGridView1_NewRowNeeded(object sender,
DataGridViewRowEventArgs e)
{
newRowNeeded = true;
}
private void dataGridView1_RowsAdded(object sender,
DataGridViewRowsAddedEventArgs e)
{
if (newRowNeeded)
{
newRowNeeded = false;
numberOfRows = numberOfRows + 1;
}
}
will fetch you the exact row refer msdn rowadded link
Depending on the operations you wish to perform after binding you could use Control.BindingContextChanged event to iterate on the grid rows:
private void dataGridView1_BindingContextChanged(object sender, EventArgs e)
{
foreach (var row in dataGridView1.Rows) {
}
}
If it's not working could you say what exactly are you trying to accomplish after binding?
How can i check for the bool condition of a check box which is in datagridview. I would like to have true if checked and false if it was unchecked. Can any one help me.
Is it possible to handle this in dataGridView_CellContentClick
This is addressed a little bit on the MSDN pages for the DataGridView here and here.
In particular they say:
For clicks in a DataGridViewCheckBoxCell, this event occurs before the
check box changes value, so if you do not want to calculate the
expected value based on the current value, you will typically handle
the DataGridView.CellValueChanged event instead. Because that event
occurs only when the user-specified value is committed, which
typically occurs when focus leaves the cell, you must also handle the
DataGridView.CurrentCellDirtyStateChanged event. In that handler, if
the current cell is a check box cell, call the DataGridView.CommitEdit
method and pass in the Commit value.
So they recommend against using the CellClick type events (since they never push the value until you leave the cell) but instead use CurrentCellDirtyStateChanged and the CommitEdit method.
So you end up with:
dataGridView1.CurrentCellDirtyStateChanged += new EventHandler(dataGridView1_CurrentCellDirtyStateChanged);
dataGridView1.CellValueChanged += new DataGridViewCellEventHandler(dataGridView1_CellValueChanged);
void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (dataGridView1.Columns[e.ColumnIndex].Name == "CB")
{
MessageBox.Show(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString());
}
}
void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
And as for getting the checked value - this is just the Value property of the DataGridViewCheckBoxCell.
So if you go:
dataGridView1.Rows[rowindex].Cells[cellindex].Value
you get a boolean value which corresponds to the checkbox (after the change has been committed).
if the checkbox is defined in the designer it would be as simple asreferring to the checkbox´s name and checking its "checked" property for true/false.
But i suspect you are adding the checkbox to the datagrid by code?
in this case youll have to save a reference to the checkbox somwhere.
If i where you i would add all the checkboxes that i add to the datagrid to a list or if you want to refer to them by name i would add them to a dictionary.
You could also bind an event to the checkbox Checked_Changed event by selecting it and clicking the little bolt icon in the properties panel and finding the checkedChanged-event and doubleclicking it.
in the event-code you can obtain the checkbox clicked by typing:
CheckBox mycheckbox = sender as CheckBox;
and then refering to mycheckbox.checked to get a bool for if its checked or not.
You can try to get this in this fashion, say in case you are looping the grid the based on the index you can find the checked state.
bool IsChecked = Convert.ToBoolean((dataGridView1[ColumnIndex, RowIndex] as DataGridViewCheckBoxCell).FormattedValue))
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
var checkcell = new DataGridViewCheckBoxCell();
checkcell.FalseValue = false;
checkcell.TrueValue = true;
checkcell.Value = false;
dataGridView1[0, 0] = checkcell; //Adding the checkbox
if (((bool)((DataGridViewCheckBoxCell)dataGridView1[0, 0]).Value) == true)
{
//Stuff to do if the checkbox is checked
}
}
It works 100 %.
private void grd_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
grd.CommitEdit(DataGridViewDataErrorContexts.Commit);
bool Result = Convert.ToBoolean((grd[e.ColumnIndex, e.RowIndex] as DataGridViewCheckBoxCell).Value);
}