Compare cells value in gridview for greater value c# - c#

i want to check if obtained marks are not greater than total marks in a gridview while entering data in runtime. what is the best way to implement that?
the logic i have developed is something like this:
if(DG_Result .Rows .Count >0)
{
for(int x=0;x<DG_Result .Rows .Count ;x++)
{
if(DG_Result .Rows [x].Cells ["DGTotal"].Value !="" & DG_Result .Rows [x].Cells ["DGObt"].Value !="")
{
if(Convert .ToInt32(DG_Result .Rows [x].Cells ["DGObt"].Value)>Convert .ToInt32(DG_Result .Rows [x].Cells ["DGTotal"].Value ))
{
DG_Result.Rows[x].Cells["DGObt"].Value = "";
MessageBox.Show("Obtained Marks Cannot be greater than Total Marks");
}
}
}
}
but i am not sure which event shall i use for this. i used timer but its not working. any suggestions? Cheers

Attach an event handler to your datagridview. Imaging it is called dataGridView1:
this.dataGridView1.CellValidating += new
DataGridViewCellValidatingEventHandler(dataGridView1_CellValidating);
Then write the event handler where you will have your validation logic:
private void dataGridView1_CellValidating(object sender,
DataGridViewCellValidatingEventArgs e)
{
string headerText =
dataGridView1.Columns[e.ColumnIndex].HeaderText;
// Abort validation if cell is not in the target column.
// The target column is the column you want to validate
if (!headerText.Equals("TargetColumn")) return;
// Confirm that the cell is not empty.
if (string.IsNullOrEmpty(e.FormattedValue.ToString()))
{
dataGridView1.Rows[e.RowIndex].ErrorText =
"Your error message goes here.";
e.Cancel = true;
}
}
You can read more about validation here.

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;
}
}
}

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..

Using DataGridViewComboBoxColumn for distinct options

I'm modifying a Winforms application in .NET 3.5.
I have a DataGridViewComboBoxColumn populated with some hard coded options as shown below.
//
// dgvCol_PropName
//
this.dgvCol_PropName.DisplayStyle = System.Windows.Forms.DataGridViewComboBoxDisplayStyle.ComboBox;
this.dgvCol_PropName.HeaderText = "Property Name";
this.dgvCol_PropName.Items.AddRange(new object[] {
"Option1",
"Option2",
"Option3"});
this.dgvCol_PropName.Name = "dgvCol_PropName";
this.dgvCol_PropName.Width = 150;
I would like to make the selection of these options distinct so that once an option exists in the grid then it can't be selected again (The user should edit the current row or delete and re-enter it).
Is there a quick way to do this?
I thought I'd share my final solution in case it helps anyone else. My CellValidating event handler is below:
/// <summary>
/// Handle the validation event on the cell so that only properties that have not already been specified can be selected
/// </summary>
private void dg_FTPS_ExProps_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
var dataGrid = sender as DataGridView;
if (dataGrid != null)
{
// Only validate if that event is generated for the Property Name column
string headerText = dataGrid.Columns[e.ColumnIndex].HeaderText;
// Abort validation if cell is not in the PropertyName column.
// Rejected using the column index in case the column order changes but
// equally, there will be problems if the column header changes. (Pay your money and take a chance)
if (headerText.Equals("Property Name"))
// if (e.ColumnIndex == 0)
{
// Count the number of times the property exists in the table
int propertyCount = 0;
foreach (DataGridViewRow row in dg_FTPS_ExProps.Rows)
{
if( row.Cells[ e.ColumnIndex ].EditedFormattedValue.ToString().Equals( e.FormattedValue) == true )
{
propertyCount++;
}
}
// Check if multiple entreies have tried to be applied
if (propertyCount > 1)
{
e.Cancel = true;
}
}
}
}
I'd have liked to use LINQ to count the number of instances but I'm still learning that so I stuck to what I know.
Try using this event DataGridView.CellValidating in the body of the event just check if there is another row with same value and if there is just set e.Cancel to true.

How to add different icons/images to datagridview row header in c#?

I want to add different image to c# windows form datagridview row header dynamically. it should be do like check any cell value and if it>10 display some image,else display other image.How to do this one?please help me...........
Add a OnRowDataBound event handler to the GridView
In the event handler - check for the header and process each column accordingly
protected virtual void OnRowDataBound(GridViewRowEventArgs e) {
if (e.Row.RowType == DataControlRowType.Header) {
// process your header here..
}
}
For more info go here: http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridviewroweventargs.row.aspx
You can add images to DataGridView row headers in the DataGridView.RowPostPaint event.
Here's a link to an article on CodeProject that appears to describe this fairly well (I haven't tried to code myself): Row Header Cell Images in DataGridView
You can use the RowPostPaint event to extract the value you want to test against to determine which icon you want to display. Do this by using the event's RowIndex property with the index value of the column you're interested in.
Something like this should serve as a starting point:
private void dataGridView1_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e) {
// As an example we'll check contents of column index 1 in our DGV.
string numberString = dataGridView1.Rows[e.RowIndex].Cells[1].Value as string;
if (numberString != null) {
int number;
if (Int32.TryParse(numberString, out number)) {
if (number > 10) {
// Display one icon.
} else {
// Display the other icon.
}
} else {
// Do something because the string that is in the cell cannot be converted to an int.
}
} else {
// Do something because the cell Value cannot be converted to a string.
}
}
I'm not exactly sure how to add images... but this link has a good example of writing numbers in the row headers, so you could update it with the >10 condition, to display your image.
.

How to disable a row by selecting value from comboBox in datagridview?

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;
}

Categories

Resources