DataGridView cell is null on CellLeave - c#

I am trying to do some text processing on the contents of the cell when the cell is left. I have the following code, but I get the following exception when I enter any text into the cell and then leave it.
An unhandled exception of type 'System.NullReferenceException' occurred in Program.exe
Additional information: Object reference not set to an instance of an object.
If I break and mousehover above .value it is indeed null, but I have entered data into the cell! So what gives?
private void dataGridView1_CellLeave(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 3)
{
string entry = "";
MessageBox.Show(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString());
MakeTextFeet(entry);
}
if (e.ColumnIndex == 4)
{
string entry = dataGridView1[e.ColumnIndex, e.RowIndex].Value.ToString();
MakeTextFeet(entry);
}
}

The value of a cell is in a transient state when the DataGridView CellLeave event fires. This is because DataGridView may be bound to a datasource and the change will not have been commited.
Your best option is to use the CellValueChanged event.

Add some checks:
DataGridViewCell MyCell = dataGridView1[e.ColumnIndex, e.RowIndex];
if (MyCell != null)
{
if (MyCell.Value != null)
{
}
}

I think you want to handle CellEndEdit rather than CellLeave.
On CellLeave, an edited cell's Value property is still unchanged (i.e. null for an empty cell as you observed by breaking and inspecting Value). On CellEndEdit, its new value has been set.
Try something like this, wherein I have tried to generally stick to your original code:
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
DataGridViewCell cell = dataGridView1[e.ColumnIndex, e.RowIndex];
if (e.ColumnIndex == 3 || e.ColumnIndex == 4)
{
string entry = "";
if (cell.Value != null)
{
entry = cell.Value.ToString();
}
MessageBox.Show(entry);
MakeTextFeet(entry);
}
}

I think you are leaving a blank cell and trying to process its value.
when you will leave a blank cell value of following code:
string entry = dataGridView1[e.ColumnIndex, e.RowIndex].Value.ToString();
value in the string entry will be blank space(entry="")
and when you are processing this value further by passing it to another function[ MakeTextFeet(entry);] it is giving you error.
Solution from my point of view for this problem is>>>
put each line of code in above method also and MakeTextFeet(Entry) also in try block.
When you will write catch block leave that block empty.
Eg.
try
{
.
.
.
}
catch(Exception)
{
}
By this thing your exception will naturally get caught but since its nigligible, it will not show you.

Related

Make the first character upper case of a string in Win Form DataGridView C#.NET

So, I have a data grid view in my C# Win Form application, the cells are editable by default, now I want whenever something is typed in those cell the end value should be treated as Upper Case First, so which means If any user types:
*string => String
example => Example
another => Another
chaRactEr => ChaRactEr*
I can do this in my code in the Cell Value Changed event, but when I do this in the Cell Value Changed event and set the value of that cell as the formatted string (Which is required from end-user) the event gets triggered twice. I can't let this happened since there is a database functionality triggering in this event.
I have tried capturing the cell value in other event like Cell Leave, Cell Enter and other events, but never can I capture it.
So I need to know, If there is a any property or characteristic of the Data Grid View in C#.NET which would make the first character of the value as upper case?
Any alternate suggestion to this would also be really helpful.
You can use this code:
bool bchange = false;
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (bchange == false)
{
bchange = true;
String oritext = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString();
String newtext= oritext.First().ToString().ToUpper() + oritext.Substring (1);
//Update Database
//Update cell
dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = newtext;
}
else
{
bchange = false;
}
}
DataGridView has an event 'CellFormatting'. You can go for something like this:
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (e.Value != null)
{
string str = (string)e.Value;
str = char.ToUpper(str[0]) + str.Substring(1);
e.Value = str;
}
}
I can only guess you may be neglecting that when the code “changes” the value in the “cell” that called the CellValueChanged event, will obviously “fire” the CellValueChanged event again when its value is changed to have an upper case string!
To avoid this circular reference, simply turn the event “off” (before you change the cells value), change the cells value… the event will not fire… then turn the event back “on" after the value has changed.
Example; Below checks to see if the cell changed is in column 0, changes the string in the cell to make the first character an upper case character. The code utilizes a text box on the form that will contain text indicating when the CellValueChanged event is fired. If the code runs with the commented code as posted, the text box will contain two (2) entries every time a cell value in column one changes. UN-commenting the two lines of code will show the text box entry will have only one (1) entry. Sandwich the line of code that “changes” the cells value between the line of code that turns the event “off” and the line of code that turns it back “on”. Hope this makes sense.
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e) {
if (e.RowIndex >= 0 && e.ColumnIndex >= 0) {
if (e.ColumnIndex == 0 && dataGridView1.Rows[e.RowIndex].Cells[0].Value != null) {
string currentData = dataGridView1.Rows[e.RowIndex].Cells[0].Value.ToString();
string newData = char.ToUpper(currentData[0]) + currentData.Substring(1);
//dataGridView1.CellValueChanged -= new DataGridViewCellEventHandler(dataGridView1_CellValueChanged);
dataGridView1.Rows[e.RowIndex].Cells[0].Value = newData;
//dataGridView1.CellValueChanged += new DataGridViewCellEventHandler(dataGridView1_CellValueChanged);
textBox3.Text += "CellValueChanged fired!" + Environment.NewLine;
}
}
}

C# datagridview cell value edit is undone after changing current cell

I hope you can help me. I didn't find a solution which fits my problem by googling.
I have a DataGridView with no bound data. When the user double-clicks in a cell he can write a new value into the cell. Based on the change, the value in the neighbour-cell is changed too. This is working properly so far.
Now I want to set some conditions, like thresholds and if the user is out of the range the value in the edited cell should be corrected.
The value in the neighbour-cell is still calculated right, but the value in the user-edited cell always stays at the user input value.
I already tried several combinations of BeginEdit() and CurrentCell..., but always the same.
Here is my actual code for the cellvalueChanged Event:
private void dgSpotInfo_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (cellvaluechangend)
{
cellvaluechangend = false;
int mod_Int_index = dgSpotInfo.Columns.IndexOf(dgSpotInfo.Columns["col_modifiedIntensity"]);
dgSpotInfo.EditMode = DataGridViewEditMode.EditProgrammatically;
dgSpotInfo.BeginEdit(true);
int val;
if (e.ColumnIndex == mod_Int_index) // if the modified Intensity value is changed
{
val = (Convert.ToInt32(dgSpotInfo[mod_Int_index, e.RowIndex].Value) - Convert.ToInt32(spot_analysis.GetFoundSpots[e.RowIndex].ModifiedIntensity));
// here is tested if the value is too high
if (Convert.ToInt32(dgSpotInfo[mod_Int_index, e.RowIndex].Value) > 255)
{
// here is the problem, during debugging the value is displayed right,
// but afterwards the current cell it is displayed as the too high value again
dgSpotInfo[mod_Int_index, e.RowIndex].Value = "255";
val = (Convert.ToInt32(dgSpotInfo[mod_Int_index, e.RowIndex].Value) - Convert.ToInt32(spot_analysis.GetFoundSpots[e.RowIndex].ModifiedIntensity));
}
dgSpotInfo.CurrentCell = dgSpotInfo[modifier_index, e.RowIndex];
dgSpotInfo[modifier_index, e.RowIndex].Value = Convert.ToString(val);
}
dgSpotInfo.EndEdit();
dgSpotInfo.EditMode = DataGridViewEditMode.EditOnKeystrokeOrF2;
dgSpotInfo.ReadOnly = true;
}
}
and here for my clicking event:
private void dgSpotInfo_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)
{
// Testing if the clicked cell is allowed to change
if (((e.ColumnIndex == dgSpotInfo.Columns.IndexOf(dgSpotInfo.Columns["col_modifiedIntensity"])) || (e.ColumnIndex == dgSpotInfo.Columns.IndexOf(dgSpotInfo.Columns["col_Modifier"]))) && e.RowIndex >= 0)
{
dgSpotInfo.CurrentCell = dgSpotInfo[e.ColumnIndex, e.RowIndex];
dgSpotInfo.ReadOnly = false;
dgSpotInfo.BeginEdit(true);
cellvaluechangend = true;
}
}
I hope I descriped my problem understandable and you can help me.
Tanks!
If someone has a similar problem:
I solved the problem by adding a CellEndEdit event. After the user edited the cell I am doing the threshold validation like above now in the CellEndEdit event handler. I don't know why, but maybe it is so, that in the event handler which is caused by the editing you cannot undo the editing.

DataGridView default value on validation failure

I am working with a DataGridView text column. The column is bound to a decimal column in a DataTable.
If I edit the cell to have an empty value and then tab out I get an exception about an issue with parsing a decimal.
I understand why this is happening and to resolve it I'd like to just force the value to be "0.00" but I can't seem to get that to work.
I tried the following but it didn't work:
private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
if (e.ColumnIndex == amountIdx)
{
if (e.FormattedValue == "")
dataGridView1[e.ColumnIndex, e.RowIndex].Value = "0.00";
}
}
Instead of setting the value I can set e.Cancel = true but that just leaves it in edit mode which isn't what I really want.
change:
if (e.FormattedValue == "")
dataGridView1[e.ColumnIndex, e.RowIndex].Value = "0.00";
to:
if (e.FormattedValue == "")
dataGridView1[e.ColumnIndex, e.RowIndex].Value = "0.00m";
On using "M/m" to annotate decimal values.
I figured it out. The value seems to be reset after CellValidating fires. Instead of updating the actual underlying value I had to set the EditingControl back to "0.00". After CellValidating is finished by new value is saved to the data source.

How to convert DataGridViewComboBoxCell to DataGridViewTextBoxCell

I searched a lot for this error many same question is already asked, but its not solving my problem.
I am getting
Operation is not valid because it results in a reentrant call to the SetCurrentCellAddressCore function.
The scenario is I have datagridview with TextboxColumn I am using CellBeginEdit to convert it in ComboBoxColumn, and after CellValidate I again change ComboBoxColumn to TextboxColumn. The codes works for all. but getting said error in exact line e.RowIndex = 2 throws this exception, but others rows doses not show error. if I omit this error and continue then e.RowIndex = 2 cell value comes blank, and other rows value work.
Here is the code of CellBeginEdit
if (e.ColumnIndex == 2 && e.RowIndex >= 0)
{
try
{
string s = Convert.ToString(_dgvCoarseAggegateTest[e.ColumnIndex, e.RowIndex].Value);
string s1 = Convert.ToString(_dgvCoarseAggegateTest[e.ColumnIndex, 0].Value);
DataGridViewComboBoxCell c = new DataGridViewComboBoxCell();
string _SizeName = _cGetParrent._mGetParentCellValue(ref _dgvCoarseAggegateTest, e.RowIndex, 1);
_mFillSieveSizeGridCombo(_mGetMetalSizeID(_SizeName), ref c); // Here My Combo Will GetValues from SQL and it Returning Value
_dgvCoarseAggegateTest[e.ColumnIndex, e.RowIndex] = c; // Heres the error When e.RowIndex == 2 and if e.RowIndex != 2 then no error
_dgvCoarseAggegateTest[e.ColumnIndex, e.RowIndex].Value = s;
_dgvCoarseAggegateTest[e.ColumnIndex, 0].Value = s1;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
How to resolve this.
UPDATE :
No rows there user will add new row and select values, the base thing is i want to show combo and fill values from database, the fill values is depends on condition, so every time new values will come,
Sample Data
testTable
1 A
2 B
3 C
4 D
5 E
6 F
7 G
8 H
9 I
In column1 I added one combo with values from 1 to 9, in _mFillSieveSizeGridCombo I am passing id to sql server 2008 and filling combo using Combo.Item.Add(x) method.
There is a flag inside SetCurrentCellAddressCore() preventing any re-entrant call corrupting internal values of DataGridView. Usaully an event was raised with the flag = true and reset at the end of event.
To workaround this, you can simply add a wrapper of BeginInvoke() inside the event, to get your process run after the event with async.
EDIT
The issue can be reproduce in EditOnEnter mode, and the setter of cell outside the event in BeginInvoke results the indefinite loop
private bool _suppressCellBeginEdit = false;
private void dgv_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
var dgv = sender as DataGridView;
if (_suppressCellBeginEdit)
return;
if (e.ColumnIndex == 2 && e.RowIndex >= 0)
{
string s = Convert.ToString(dgv[e.ColumnIndex, e.RowIndex].Value);
string s1 = Convert.ToString(dgv[e.ColumnIndex, 0].Value);
DataGridViewComboBoxCell c = new DataGridViewComboBoxCell();
c.Items.Add(string.Format("x{0}:y{1} {2}", e.RowIndex, e.ColumnIndex, 0));
c.Items.Add(string.Format("x{0}:y{1} {2}", e.RowIndex, e.ColumnIndex, 1));
c.Items.Add(string.Format("x{0}:y{1} {2}", e.RowIndex, e.ColumnIndex, 2));
// special handling
if (e.RowIndex == e.ColumnIndex)
{
this.BeginInvoke(new Action(() =>
{
_suppressCellBeginEdit = true;
this.Invoke(new Action(() =>
{
c.Value = s;
dgv[e.ColumnIndex, e.RowIndex] = c;
dgv[e.ColumnIndex, 0].Value = s1;
}));
_suppressCellBeginEdit = false;
}));
}
else
{
c.Value = s;
dgv[e.ColumnIndex, e.RowIndex] = c;
dgv[e.ColumnIndex, 0].Value = s1;
}
}
}
As you can tell from the trouble you are having implementing this, DataGridView is very unhappy about you trying to pull the floor mat. It explicitly forbids changing the cell object at critical moments. While it is handling an event itself is such a critical moment. A generic problem with events, called re-entrancy. The trouble you are having with #Eric's approach shows that it is indeed a tricky issue to solve.
So what you do not want to do is modify the cell type or reference. Keep your eyes on the ball, what you really want to do is modify the content of the dropdown list. That is not a problem. Get back to the designer and change the ColumnType property of the column to DataGridViewComboBoxColumn. And use the CellBeginEdit event to dynamically alter the combobox items collection. A simple example:
private void _dgvCoarseAggegateTest_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) {
var dgv = (DataGridView)sender;
if (e.ColumnIndex == 2) {
var cell = (DataGridViewComboBoxCell)dgv.Rows[e.RowIndex].Cells[e.ColumnIndex];
cell.Items.Clear();
// Run your dbase query here to fill cell.Items
//...
// We'll just fake it here for demo purposes:
cell.Items.Add(e.RowIndex.ToString());
cell.Items.Add((e.RowIndex+1).ToString());
cell.Items.Add((e.RowIndex+2).ToString());
}
}
Here is a workaround: In the CellBeginEdit event first check to see if the ColumnType is DataGridViewComboBoxCell. If it isn't we cancel the event, call a function that changes the column type and then call the event once more:
void switchCellType(object sender, DataGridViewCellCancelEventArgs e)
{
DataGridViewComboBoxCell c = new DataGridViewComboBoxCell();
// prepare the cell:
//..
// fill the drop down items..
c.Items.Add("1"); // use
c.Items.Add("2"); // your
c.Items.Add("3"); // code here!
DGV[e.ColumnIndex, e.RowIndex] = c; // change the cell
DGV_CellBeginEdit(sender, e); // restart the edit with the original parms
}
private void DGV_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
DataGridViewCell cell = DGV[e.ColumnIndex, e.RowIndex];
if (!(cell is DataGridViewComboBoxCell))
{
e.Cancel = true;
switchCellType(sender, e);
return;
}
//..
Now your code can proceed, obviously without the cell changing. Possibly you want to pass in the text value to set as well..
Note that you will have to make sure that the CellEndEdit event doesn't revert the change before its time!! Maybe a flag, maybe in the Tag will help. If you want I can have a look at your CellEndEdit code, if there is any..

Hide a cell from gridview

I have a winform c# SQL app in which i retrieve some values to a datagrid view and from there on wards i will display them to a user.
however there are certain gridcells which have values that i don't want to show to the user, and i want to hide them,
here is my code to hide cell values.
CurrencyManager cm = (CurrencyManager)BindingContext[dataGridView1.DataSource=dmz.Tables[0]];
foreach (DataGridViewRow dgvr in dataGridView1.Rows)
{
if (dgvr.Cells[51].Value.ToString() == "N/A") //object reference not set to an instance of the object exception is thrown
{
cm.SuspendBinding();
dgvr.Visible = false;
}
there is an object reference not set to an instance of the object exception thrown...
what is triggering the error?
Please help...
Change
if (dgvr.Cells[51].Value.ToString() == "N/A")
to
if (dgvr.Cells[51].Value??"").ToString() == "N/A")
or
if (dgvr.Cells[51].Value!=null && dgvr.Cells[51].Value.ToString() == "N/A")
You can use the DataGridView_CellFormatting event method .
Like this:
private void dgvr_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if(dgvr.Rows[e.RowIndex].Cells["51"].Value!=null && dgvr[51].Value.ToString()=="N/A")
{
dgvr.Rows[e.RowIndex].Cells["51"].Value="";
}
}

Categories

Resources