C# DataGridView Reentrant call issue - c#

C# winforms
I have a DataGridView populated from a list of objects. The DataGridViewis set to use fullrowselect with multiselect off.
I have a button above the table that they can use to select the next row. I have a Checkbox above the table that they use to change data in one of the cells of the selected row. The button and the Checkbox both work independently without issue.
I'd like to make it so that when they check that Checkbox it changes the data in the selected row cell and then selects the next row in the table.
No matter how I go about this, I either get the reentrant call error immediately or when I later try to select that row again.
I have tried BeginInvoke, BackGroundWorker, using a timer to change the row selection, setting a variable to remember the row and changing the value after the row selection has changed or after the row has validated. Every attempt gives me the same error.
My code is much too long to post here, but I may be able to create a simple app to demonstrate the issue if needed.
Please help.
Here is the code:
private void chkDone_CheckedChanged(object sender, EventArgs e)
{
ProcedureCode proc = getCode(gridCodes.SelectedRows[0].Cells[3].Value + "");
proc.done = chkDone.Checked;
setPnlProgress();
if(chkDone.Checked)
{
btnNext_Click(sender, e);
}
}
private void btnNext_Click(object sender, EventArgs e)
{
int cRow = gridCodes.SelectedRows[0].Index;
if (cRow < gridCodes.RowCount - 1)
{
gridCodes.CurrentCell = gridCodes[0, cRow + 1];
}
}
Here is a screenshot of the table and checkbox:Click to see screenshot
The second checkbox labled Done is the one that changes the value in the cell of the selected row. The third circle button selects the next row.

I found that the the checkbox CheckChanged event was being fired when I went to the next row as well as when the user clicked the checkbox. I added a flag to skip any action during the row entering phase and this resolved the reentrant error.

Related

C# DataGridView 1st CheckBox Cell redrawing as unchecked. Why?

Issue Solved - Posted for reference.
Hi, I have a strange error occurring.
I have a DataGridView that I am using to store a list of records, these records are being updated from a source by a BackgroundWorker. There is a CheckBox Column that allows the user to select records from the DataGridView for processing.
When I check the CheckBox the first row(and only the first row), the checkbox does not seem to refresh correctly and displays as unchecked. The checkbox is still being treated as checked and the logic tied to it is working correctly. This is a cosmetic issue that may confuse users.
any other CheckBox in the DataGridView draws correctly at all times.
Clicking anywhere on the DataGridView causes the CheckBox state to redraw correctly.
It seems like a redrawing issue, but I am having trouble tracking down why it is drawing like this.
Some details of relevance.
It is necessary for me to reload the dataset with each refresh.
I have set the cell highlight colors to be the same as the non-highlighted ones.
I have a routine that checks the Checked state of the CheckBoxes, records the records that have been selected and rechecks the checkboxes when the dataset has been replaced. -This is working correctly
See the following code.
private void BgwDocketList_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
var checkedRows = from DataGridViewRow r in Dgv_Batch.Rows
where Convert.ToBoolean(r.Cells[0].Value) == true
select r;
List<int> L = new List<int>();
foreach (DataGridViewRow x in checkedRows)
{
L.Add((int)x.Cells[1].Value);
}
Dgv_Batch.DataSource =e.Result;
foreach (DataGridViewRow v in Dgv_Batch.Rows)
{
if (L.Count(x=>x==(int)v.Cells[1].Value)>0)
{
v.Cells[0].Value = true;
}
}
}
Have tried changing the selected cell programmatically
I have tried setting focus to the DataGridView in an attempt to programmatically recreate the effect of clicking on the control. This does not redraw the checkbox. only a mouse click seems to do this.
...Ok...
While Writing this I have managed to solve the problem. I guess it helps to write down the steps to ensure they are checked out.
The issue was that after updating the checkboxes I needed to use
DataGridView.EndEdit()
I would have expected that routine to have worked on the last record last as opposed to the first. I guess this relates back to the DataGridView.DataGridViewSelectedRowCollection containing a reversed index.
I have posted this Question anyway in the hope that It may help someone with the same issue.
Utilize
DataGridView.EndEdit();
This will solve the problem.

Show the selected row record in textbox/label

How do I make the selected row record from a DataGridView show in a TextBox? I got some TextBox and Label in a Form. I want the text inside the TextBox/Label to change when the user selects a row record from the DataGridView. I tried the following code to make it happen, but it doesn't work
private void ItemTable_RowHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
label_itemid_show.Text = ItemTable.Rows[e.RowIndex].Cells[0].Value.ToString();
text_itemname.Text = ItemTable.Rows[e.RowIndex].Cells[1].Value.ToString();
text_itemprice.Text = ItemTable.Rows[e.RowIndex].Cells[2].Value.ToString();
text_itemstock.Text = ItemTable.Rows[e.RowIndex].Cells[3].Value.ToString();
}
I'm working on a project that includes a features similar to yours. Currently I select a record in a datagridview and need to show it's values to textboxes so that any values can be edited.
This is how I tackle the problem.
Models.Item item = DAL.ItemDAL.GetItem(Convert.ToInt32(ItemDataGrid.CurrentRow.Cells[0].Value));
tbModifyItemID.Text = Convert.ToString(item.ItemID);
tbModifyItemName.Text = item.ItemName;
It's the ItemDataGridView.CurrentRow.Cells[0].Value that finds me the ItemID of the selected record.
In your case it's [DataGridName].CurrentRow.Cells[FieldNo, starting at 0].Value.ToString();
This allows you to click on any cell in the record and still retrieve the specified cell in the code.
Hope it helps c:
PS:
If you put it inside a
private void ItemDataGrid_SelectionChanged(object sender, EventArgs e)
method it will run the code anytime you click a different cell in the datagridview.
You can use the following:
lblDetails.Text = dgMainGrid.SelectedRows[0].Cells[1].Value.ToString();
lblDetails: A label on the form.
dgMainGrid: DataGrivView on the form.
PS: Just make sure you select the row inside the datagrid and not any particular cell, row selecting is done by clicking on the left of your first column i.e. the row selector column which gets added at the run time in WinForms.

WPF xamgrid row by row commit behaviour for new row not working

I am using XamGrid control for datainput from end user. Databinding is working
For the xamgrid, I have added a new line at the bottom of the table and have kept the following settings:
IsMouseActionEditingEnabled="SingleClick" IsOnCellActiveEditingEnabled="False" AllowAddNewRow="Bottom" Style="{StaticResource addNewRowCellStyle}"/>
Now the requirement is that if user enters on the new row cell, then the active cell should be the first cell of the first row in the xamgrid so I wrote the following code in the ActiveCellChanged event to work it out
private void dataCurveGrid_ActiveCellChanged(object sender, EventArgs e)
{
Infragistics.Controls.Grids.CellBase type = dataCurveGrid.ActiveCell;
if (type is Infragistics.Controls.Grids.Primitives.AddNewRowCell)
{
if (dataCurveGrid.Rows.Count != 0)
{
dataCurveGrid.Rows[0].Cells[0].IsActive = true; } } }
The above requirement is working but
Now my hurdle is because of above ActiveCellChanged method the behaviour of data entered on new row control is getting committed cell by cell instead of row by row which is required by me and was happening before this method.
Please advice what should I do to make the user data get committed row by row.
Also please inform if any alternate method is there to solve the above user requirement and not disturb the above row by row commitment.
Thanks in advance
Rakesh
I am not completely sure that I understand your requirement, but as I much as I did, I can say that the behavior you have is expected since when you change the Active Cell from the AddNewRow to an existing Row, the AddNewRow commit its Changes.

DataGridView that always has one row selected

I'm using a DGV to show a list of images with text captions as a picklist. Their must always be a one and only one selection made in the list. I can't find a way to prevent the user from clearing the selection with a control-click on the selected row.
Is there a property in the designer I'm missing that could do this?
If I have to override the behavior in the mouse click events are there other ways the user could clear the current selection that need covered as well?
Is there a third approach I could take that's less cumbersome than my second idea?
The easiest way is to catch the SelectionChanged event and check to see if the user has unselected all rows. If so, reselect the previously selected row. Essentially, you're intercepting their action and switching the selection back. Something like this (code untested but you will get the idea):
DataGridViewRow last_selected_row;
private void dgv_SelectionChanged(object sender, EventArgs e)
{
if (dgv.SelectedRows.Count == 0)
last_selected_row.Selected = true;
else
last_selected_row = dgv.SelectedRows[0];
}
Depending on your application, it might be better to store the row index rather than a reference to the row itself. Also be sure to initialize last_selected_row and update it if you delete any rows.
Any other controls that hook the SelectionChanged event will need to safely handle the case that no rows are selected, in case they fire before the event that switches it back. They can just return immediately though, safe in the knowledge that SelectionChanged will fire again momentarily.
You could also subclass DataGridView and override the OnSelectionChanged method. Then you could reselect the last selected row before the event fires (it will fire when you call base.OnSelectionChanged).
A DGV got a property called multiselect, if you set it to false only one cell/row can be selected at a time.
Just handle the DataBindingComplete event of the datagridview like this:
private void datagridview1_DataBindingComplete(System.Object sender, System.Windows.Forms.DataGridViewBindingCompleteEventArgs e)
{
datagridview1.ClearSelection();
}

Textbox control in DataGridView

I am working on a datagridview in C# in windows application. I want to add textbox controls in DataGridView. So, when we run it then textbox should be shown in gridview and we can put value in it and My grid has 3 columns and I want to add new row in grid when I press tab on 3rd column of gridview.
How do I do this?
It's hard to provide a precise answer since your question is lacking in detail and pretty general, but to get textboxes in your DataGridView, you're going to want to add some instances of DataGridViewTextBoxColumn to the DataGridView's Columns collection. This will cause them to be populated with textboxes in each row.
To detect when the user presses tab on the 3rd column, you can add a 1-2 pixel wide fourth column and detect that it has recieved focus (almost definitely from a tab keystroke) using the OnCellEnter event.
Good luck!
So, for the "display textboxes by default portion of your question, here's the skinny:
On GridView->Edit Columns, add the columns you want to use explicitly. Then click on the link "Convert this field into a templateField". This will let you tweak the generated HTML for those cells. Say OK. Then go to GridView->Edit Templates. For your favorite Column, copy the ItemEditTemplate into the ItemTemplate. (ItemTemplate is the default. ItemEditTemplate contains the properly bound edit control.) Now all of your data fields will default to "editable."
I'm guessing you have a submit button. You'll need to tell the GridView to update the rows on submit., like so:
For Each r As GridViewRow In GridView1.Rows
Dim mon = System.Int32.Parse(CType(r.FindControl("TextBox1"), TextBox).Text)
If mon <> 0 Then GridView1.UpdateRow(r.RowIndex, False)
Next
Obviously, you'll want different logic inside there, but the basic loop/findControl/updateRow logic should apply.
Microsoft has a walkthrough on this here: Performing Bulk Updates to Rows Bound to a GridView
Try this, for example if you want to set your first column in datagridview as a textbox control:
private void dtgrdview_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 0)
{
TextBox txtbox1=new TextBox();
dtgrdview.Controls.Add(txtbox1);
Rectangle rectangle = dtgrdview.GetCellDisplayRectangle(0, e.RowIndex, true);
txtbox1.Location = rectangle.Location;
txtbox1.Size = rectangle.Size;
txtbox1.TextChanged += txtbox1_TextChanged;
txtbox1.Leave += txtbox1_Leave;
txtbox1.Visible = true;
}
}
and don't forget to add this event in the same class as like below to call it when the cell have the focus:
private void txtbox1_Leave(object sender, EventArgs e)
{
txtbox1.Visible = false;
}
private void txtbox1_TextChanged(object sender, EventArgs e)
{
dtgrdview.CurrentCell.Value = txtbox1.Text;
}
If you have any other questions, don't hesitate to ask me :)

Categories