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.
Related
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;
}
}
}
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.
I'm creating an ordering system for booking customers in, and I want a combobox in a datagridview to be able to mark a certain job as complete, and change the colour of that row to green when yes is selected, I'd like some help with this please as I have no idea how to do it, I have looked all over the internet and found nothing.
this is a screenshot of the database, any and all help would be greatly appreciated.
I'm using WinForms
thanks in advance
You have to use CellValueChanged event.
private void GridCellValueChanged(object sender, DataGridViewCellEventArgs e)
{
//just to be safe
if (e.RowIndex < 0 || e.ColumnIndex < 0)
{
return;
}
var value = dataGridView1[e.ColumnIndex, e.RowIndex].Value;
if (value != null && value.ToString() == "Yes") // is completed
{
dataGridView1.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Green;
}
else
{
dataGridView1.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.White;
}
}
hope it helps :)
You should use Datagridview value changed event. And in that event get the selected row and cell value. Based on that value you should set the selected row backcolor.
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.
Here I have a column name "Status" in which I am using ComboBox whose values are "Pending" and "Delivered" now I want that when a user selects the delivered from the ComboBox then the entire row or this control should be disabled so user could not change it again and by default its value should be "Pending" how can i do it? Is it possible to disable a single row in gridview?
You cannot disable an individual row. However you can make it readonly:
DataGridView1.Rows[rowIndex].ReadOnly = true;
(This makes row with index of rowIndex set to readonly).
For your specific example, you would want to handle the CellValueChanged event of the datagridview and have code along the lines of:
void DataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 4 && DataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString() == "Delivered")
{
DataGridView1.Rows[e.RowIndex].ReadOnly = true;
}
}
You can handle the RowChanged event and do something like
if (Status == 'Delivered')
{
e.Row.Enabled = False;
}