current cell focus problem after using cellendedit event - c#

I am designing a c# datagridview in which the enter key works as tab , back key results in moving back to previous cell . Also if the focus is at the last cell of last row of last column it creates a new row .
private void dataGridView1_KeyDown(object sender, KeyEventArgs e)
{
e.SuppressKeyPress = true;
int iColumn = dataGridView1.CurrentCell.ColumnIndex;
int iRow = dataGridView1.CurrentCell.RowIndex;
if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Right || e.KeyCode == Keys.Tab)
{
//to check if the pointer reach last column
if (iColumn == dataGridView1.ColumnCount - 1)
{
//executing when line ends
if (dataGridView1.RowCount > (iRow + 1))
{
dataGridView1.CurrentCell = dataGridView1[0, iRow + 1];
}
// fires when you reach last cell of last row and last column
else
{
dataGridView1.Rows.Add();
dataGridView1.CurrentCell = dataGridView1[0, iRow +1];
}
}
else
{
dataGridView1.CurrentCell = dataGridView1[iColumn + 1, iRow];
}
}
if (e.KeyCode == Keys.Down)
{
int c = dataGridView1.CurrentCell.ColumnIndex;
int r = dataGridView1.CurrentCell.RowIndex;
if (r < dataGridView1.Rows.Count - 1) //check for index out of range
dataGridView1.CurrentCell = dataGridView1[c, r + 1];
}
if (e.KeyCode == Keys.Up)
{
int c = dataGridView1.CurrentCell.ColumnIndex;
int r = dataGridView1.CurrentCell.RowIndex;
if (r > 0) //check for index out of range
dataGridView1.CurrentCell = dataGridView1[c, r - 1];
}
if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Left)
{
//to check if you are in first cell of any line
if (iColumn == 0)
{
//to check if you are in first cell of fist line
if (iRow == 0)
{
MessageBox.Show("you reached first cell");
}
else
{
dataGridView1.CurrentCell = dataGridView1[dataGridView1.ColumnCount - 1, iRow - 1];
}
}
else
{
dataGridView1.CurrentCell = dataGridView1[iColumn - 1, iRow];
}
}
}
Now , after this i want to edit the cell values and want to move to next cell when i press enter key , so i add the following event (as i am in cell editing mode due to this, the above key down event will not raise )
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
// MOVE TO NEXT CELL WHEN DONE EDITING
SendKeys.Send("{right}");
}
But after using the above event cellendedit , i found out that the cell is moving down to the next row(default behavior of datagridview) and then to next row's next cell(due to cellendedit) . Instead it should move to the next column same row . Please suggest me to fix this behaviour .

Your question is how to suppress the default DataGridView navigation and substitute your own. The default navigation occurs in the OnKeyDown method, and if you override it in your custom control (let's call it DataGridViewEx) you should be able to suppress the default navigation by overriding that method, making sure that you do not call the base class version for Keys.Enter and Keys.Back.
BindingList<Record> Records = new BindingList<Record>();
protected override void OnKeyDown(KeyEventArgs e)
{
if (CurrentCell != null)
{
var row = CurrentCell.RowIndex;
var col = CurrentCell.ColumnIndex;
switch (e.KeyData)
{
case Keys.Return:
col++;
// [ToDo] Allow for non-visible rows (will fail).
if(col.Equals(Columns.Count))
{
col = 0;
row++;
// Either insert after the current row as
// shown here, or add to the end of the list.
Records.Insert(row, new Record());
}
CurrentCell = this[col, row];
break;
case Keys.Back:
col--;
if(col >= 0)
{
CurrentCell = this[col, row];
}
break;
default:
base.OnKeyDown(e);
break;
}
}
}
TESTBENCH
Here's how I tested this solution after changing the two entries in MainForm.Designer.cs to use the DataGridViewEx:
namespace current_cell_focus
{
public partial class MainForm : Form
{
public MainForm() => InitializeComponent();
}
// Custom control
class DataGridViewEx : DataGridView
{
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
AllowUserToAddRows = false;
DataSource = Records;
// Format columns
Records.Add(new Record());
foreach (DataGridViewColumn col in Columns)
{
col.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
}
Records.Clear();
// Load test data
Records.Add(new Record
{
Column1 = "1",
Column2 = "2",
Column3 = "3"
});
Records.Add(new Record
{
Column1 = "4",
Column2 = "5",
Column3 = "6"
});
Records.Add(new Record
{
Column1 = "7",
Column2 = "8",
Column3 = "9"
});
}
BindingList<Record> Records = new BindingList<Record>();
protected override void OnKeyDown(KeyEventArgs e)
{
if (CurrentCell != null)
{
var row = CurrentCell.RowIndex;
var col = CurrentCell.ColumnIndex;
switch (e.KeyData)
{
case Keys.Return:
col++;
// [ToDo] Allow for non-visible rows (will fail).
if(col.Equals(Columns.Count))
{
col = 0;
row++;
// Either insert after the current row as
// shown here, or add to the end of the list.
Records.Insert(row, new Record());
}
CurrentCell = this[col, row];
break;
case Keys.Back:
col--;
if(col >= 0)
{
CurrentCell = this[col, row];
}
break;
default:
base.OnKeyDown(e);
break;
}
}
}
}
class Record
{
public string Column1 { get; set; }
public string Column2 { get; set; }
public string Column3 { get; set; }
}
}

Related

how to use enter key after cell edit in DataGridView c#

im trying to go next cell in datagridview after typing in the cell but it go to next row in same Column
** if not typing any thing in cell it working fine
how can solve that
private void dgvacc_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
int row = dgvacc.CurrentCell.RowIndex;
int col = dgvacc.CurrentCell.ColumnIndex;
try
{
if (col < dgvacc.Columns.Count - 1)
{
dgvacc.CurrentCell = dgvacc.Rows[row -1].Cells[col + 1];
dgvacc.Focus();
}
else if (col == dgvacc.Columns.Count - 1)
{
dgvacc.CurrentCell = dgvacc.Rows[row].Cells[0];
dgvacc.Focus();
}
}
catch (Exception)
{
}
}
}
Option 1
Override the Form's ProcessCmdKey to trap the Keys.Enter presses and select the next cell IF the gird is focused OR the DataGridView.EditingControl property is not null/Nothing.
public partial class YourForm : Form
{
public YourForm()
{
InitializeComponent();
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if ((dataGridView1.Focused || dataGridView1.EditingControl != null)
&& keyData == Keys.Enter)
{
SelectNextCell();
return true;
}
else
return base.ProcessCmdKey(ref msg, keyData);
}
private void SelectNextCell()
{
var col = dataGridView1.CurrentCell.ColumnIndex;
var row = dataGridView1.CurrentCell.RowIndex;
if (col < dataGridView1.ColumnCount - 1) col++;
else
{
col = 0;
row++;
}
// Optional, select the first cell if the current cell is the last one.
// You can return; here instead or add new row.
if (row == dataGridView1.RowCount) row = 0;
dataGridView1.CurrentCell = dataGridView1[col, row];
}
}
Option 2
Derive a new class from DataGridView and do the same except the focus and EditingControl checks:
[DesignerCategory("Code")]
public class DataGridViewEx : DataGridView
{
public DataGridViewEx() : base() { }
// Optional to enable/disable this feature...
public bool SelectNextCellOnEnter { get; set; } = true;
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (SelectNextCellOnEnter && keyData == Keys.Enter)
{
SelectNextCell();
return true;
}
else
{
return base.ProcessCmdKey(ref msg, keyData);
}
}
private void SelectNextCell()
{
var col = CurrentCell.ColumnIndex;
var row = CurrentCell.RowIndex;
if (col < ColumnCount - 1) col++;
else
{
col = 0;
row++;
}
if (row == RowCount) row = 0;
CurrentCell = this[col, row];
}
}
thanks for all
i found the the answer and it solve it - thanks again
private DataGridViewCell dgvEndEditCell;
private bool _EnterMoveNext = true;
[System.ComponentModel.DefaultValue(true)]
public bool OnEnterKeyMoveNext
{
get
{
return this._EnterMoveNext;
}
set
{
this._EnterMoveNext = value;
}
}
private void dgvacc_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
e.SuppressKeyPress = true;
int iColumn = dgvacc.CurrentCell.ColumnIndex;
int iRow = dgvacc.CurrentCell.RowIndex;
if (iColumn == dgvacc.Columns.Count - 1 && iRow != dgvacc.Rows.Count - 1)
{
dgvacc.CurrentCell = dgvacc[0, iRow + 1];
}
else if (iColumn == dgvacc.Columns.Count - 1 && iRow == dgvacc.Rows.Count - 1)
{
}
else
{
dgvacc.CurrentCell = dgvacc[iColumn + 1, iRow];
}
}
}
private void dgvacc_SelectionChanged(object sender, EventArgs e)
{
if (this._EnterMoveNext && MouseButtons == 0)
{
if (this.dgvEndEditCell != null && dgvacc.CurrentCell != null)
{
if (dgvacc.CurrentCell.RowIndex == this.dgvEndEditCell.RowIndex + 1
&& dgvacc.CurrentCell.ColumnIndex == this.dgvEndEditCell.ColumnIndex)
{
int iColNew;
int iRowNew;
if (this.dgvEndEditCell.ColumnIndex >= dgvacc.ColumnCount - 1)
{
iColNew = 0;
iRowNew = dgvacc.CurrentCell.RowIndex;
}
else
{
iColNew = this.dgvEndEditCell.ColumnIndex + 1;
iRowNew = this.dgvEndEditCell.RowIndex;
}
dgvacc.CurrentCell = dgvacc[iColNew, iRowNew];
}
}
this.dgvEndEditCell = null;
}
}

How to check if the quantity inserted is greater than the new stock in my Datagridview Cell

I want to create a function that will check if the quantity inserted is greater than the new stock in my Datagridview Cell ["New Stock"] to prevent the data from execution.
double qty,totalprice,discount;
double.TryParse(txtqty.Text, out qty);
double.TryParse(txttotalprice1.Text, out totalprice);
double.TryParse(txtdiscount.Text, out discount);
//Boolean to check if he has row has been
bool Found = false;
if (dataGridView1.Rows.Count > 0)
{
// Check if the product Id exists with the same Price
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (Convert.ToString(row.Cells[0].Value) == cmbproductcode.Text && Convert.ToString(row.Cells[3].Value) == txtprice1.Text)
{
//Update the Quantity of the found row
row.Cells[5].Value = Convert.ToString(qty + Convert.ToInt16(row.Cells[5].Value));
row.Cells[7].Value = Convert.ToString(discount + Convert.ToInt16(row.Cells[7].Value)); //txtqty
row.Cells[8].Value = Convert.ToString(totalprice + Convert.ToInt32(row.Cells[8].Value)); //txttotalprice
Found = true;
getprice();
}
}
if (!Found)
{
//Add the row to grid view
getinfo();
}
}
else
{
//Add the row to grid view for the first time
getinfo();
}
public double prev;
private void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
string cellValue;
int i = e.RowIndex;
cellValue = dataGridView1.Rows[i].Cells[1].Value.ToString();
prev = Convert.ToDouble(cellValue);
}
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
string cellValue;
int i = e.RowIndex;
cellValue = dataGridView1.Rows[i].Cells[1].Value.ToString();
double cur = Convert.ToDouble(cellValue);
if(isvalid(prev,cur))
dataGridView1.Rows[i].Cells[1].Value = prev.ToString();
else
dataGridView1.Rows[i].Cells[1].Value = cellValue;
}
private Boolean isvalid(double pr,double cur)
{
return cur > pr ? false : true;
}

How to check if Items already exist in datagridview

How to prevent if the new enter barcode already in the datagridview and if is exist add the quantity or sum.
Put the barcode column like datakey and search if the value exists using Datagrid.Rows.Find ([barcode value]) when you want add new row
Try This Tested Code Call dataGridview_CellEndEdit Event :
private void GvOpStock_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
try
{
if (e.ColumnIndex != 0)
for (int row = 0; row < GvOpStock.Rows.Count - 1; row++)
{
if (GvOpStock.Rows[row].Cells[1].Value != null &&
row != e.RowIndex &&
GvOpStock.Rows[row].Cells[1].Value.Equals(GvOpStock.Rows[e.RowIndex].Cells[e.ColumnIndex].Value))
{
MessageBox.Show("Duplicate");
return;
}
else
{
//Add To datagridview
}
}
}
catch (Exception ex)
{
}
}
I got an answer to my question
Boolean found = false;
if (!string.IsNullOrWhiteSpace(this.textBox1.Text))
{
if (e.KeyCode == Keys.Enter)
{
string conbarcode = this.textBox1.Text;
conbarcode = this.textBox1.TextLength == 10 ? this.textBox1.Text : Convert.ToDouble(this.textBox1.Text).ToString("0000000000").ToString();
foreach (DataGridViewRow row in this.dataGridView1.Rows)
{
if (row.Cells[0].Value.Equals(conbarcode))
{
// row exists
found = true;
row.Cells["qty"].Value = Convert.ToInt32(row.Cells["qty"].Value) + 1;
row.Cells["qty"].Selected = true;
//MessageBox.Show("Row already exists");
break;
}
}
if (found)
{
this.textBox1.BackColor = Color.LightGreen;
return;
}

C# Programmatically created datagridview - DataGridViewCheckBoxColumn cellValueChanged check state always returning FALSE

In C#, I cannot get DataGridViewCheckBoxColumn event to work. It always get a FALSE value even though I’ve clicked on the checkbox. The other datagridviews (text and combobox) columns work fine. Here is what I am doing…
OK, so I am dynamically creating datagridviews (DGVs) at runtime in my constructor based on how many tab sheets there are in the tab control which is determined by the number of weeks in any given date range i.e. one DGV per tab page (where you tab page for each week)
for (int i = 0; i < wcNumWeeks; i++)
{
foreach (DataRow dr in wbDatesDT.Rows)
{
if (Convert.ToInt16(dr["tabNo"].ToString()) == i + 1)
{
wcDate = Convert.ToDateTime(dr["wcDate"].ToString());
break;
}
}
weeksTabControl.TabPages.Add(wcDate.ToShortDateString());
weeksTabControl.TabPages[i].AutoScroll = true;
weeksTabControl.TabPages[i].Width = 1500;
weeksTabControl.TabPages[i].Height = 700;
weeksTabControl.TabPages[i].Controls.Add(new DataGridView()
{
Name = "dataGridView" + (i + 1).ToString(),
Dock = DockStyle.Fill,
Width = 1450,
Height = 650,
Anchor = (AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right),
ScrollBars = System.Windows.Forms.ScrollBars.Both,
AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells
});
}
Again in the constructor, for each datagridview created I am creating event as follows:
foreach (Control thisControl in weeksTabControl.Controls)
{
if (thisControl.GetType() == typeof(TabPage))
{
foreach (Control dgv in thisControl.Controls)
{
if (dgv.GetType() == typeof(DataGridView))
{
BuildWhiteboardDGV((DataGridView)dgv);
PopulateWhiteboardDGV((DataGridView)dgv);
wbDataGridView = (DataGridView)dgv;
wbDataGridView.CellMouseUp += new DataGridViewCellMouseEventHandler(wbDataGridView_CellMouseUp);
wbDataGridView.CellEndEdit += new DataGridViewCellEventHandler(wbDataGridView_CellEndEdit);
wbDataGridView.CurrentCellDirtyStateChanged += new EventHandler(wbDataGridView_CurrentCellDirtyStateChanged);
wbDataGridView.CellValueChanged += new DataGridViewCellEventHandler(wbDataGridView_CellValueChanged);
}
}
}
}
The events themselves are as follows:
void wbDataGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (wbDataGridView.IsCurrentCellDirty)
{
wbDataGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
 
void wbDataGridView_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
try
{
if (e.ColumnIndex >= 13 && e.ColumnIndex <= 15)
{
System.Drawing.Point cur = new System.Drawing.Point(e.ColumnIndex, e.RowIndex);
DataGridViewCheckBoxCell curCell = (DataGridViewCheckBoxCell)wbDataGridView[cur.X, cur.Y];
if (curCell.Value != null && (bool)(curCell.Value) == true)
{
MessageBox.Show("TRUE");
}
else if (curCell.Value != null && (bool)(curCell.Value) == false)
{
MessageBox.Show("FALSE");
}
else
{
MessageBox.Show("NULL");
}
}
return;
}
catch (Exception ex )
{
MessageBox.Show("wbDataGridView_CellValueChanged() ERROR - " + ex.Message + " --> " + ex.InnerException.ToString());
return;
}
}
Where am I going wrong?
OK.... I think I've sorted it.
In my CellMouseUp() event, I had not catered for the LEFT button.
Therefore, by now adding that, the CellValueChanged() event works correctly and captures the correct DataGridViewCheckCellColumn check state : TRUE when checked and FALSE when unchecked.
public void wbDataGridView_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left && e.RowIndex != -1) // added this and it now works
{
this.rowIndex = e.RowIndex;
this.colIndex = e.ColumnIndex;
this.wbDataGridView = (DataGridView)sender;
return;
}
if (e.Button == System.Windows.Forms.MouseButtons.Right && e.RowIndex != -1)
{
this.rowIndex = e.RowIndex;
this.colIndex = e.ColumnIndex;
this.wbDataGridView = (DataGridView)sender;
return;
}
}
Thanks for your comments though. Much appreciated.
Jobs a good un !!!!

Gridview Dynamic formatting according to conditions

I have this code on RowDataBound that alternates the color of the cells and also add an onclick event on the cells. The data comes dynamically from a stored procedure so the gridview has only one control. The ButtonField.
I want to have white color for cells that hasn’t any data inside, how can I achieve this?
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
{
string back1 = "url('Images/GridBack1.jpg')";
string back2 = "url('Images/GridBack2.jpg')";
if (e.Row.RowType != DataControlRowType.DataRow)
return;
for (int i = 0; i < e.Row.Cells.Count; i++)
{
TableCell Cell = e.Row.Cells[i];
// if both row and column are odd, color them black
// if both row and column are even, color them white
if (((e.Row.RowIndex % 2 == 1) && (i % 2 == 1)) ||
((e.Row.RowIndex % 2 == 0) && (i % 2 == 0)))
{
if (string.IsNullOrEmpty(e.Row.Cells[i].Text)) //Edit
{
e.Row.Cells[i].BackColor = Color.Blue;
e.Row.Cells[i].ForeColor = Color.White;
}
else
{
e.Row.Cells[i].Width = Unit.Pixel(450);
e.Row.Cells[i].Height = Unit.Pixel(67);
e.Row.Cells[i].Style.Add("background-image", back1);
//e.Row.Cells[i].Style.Add("width", "150px");
//e.Row.Cells[i].Style.Add("word-wrap","break-word");
e.Row.Cells[i].Attributes.Add("align", "center");
}
}
else
{
if (string.IsNullOrEmpty(e.Row.Cells[i].Text)) //Edit
{
e.Row.Cells[i].BackColor = Color.Blue;
e.Row.Cells[i].ForeColor = Color.White;
}
else
{
e.Row.Cells[i].Width = Unit.Pixel(450);
e.Row.Cells[i].Height = Unit.Pixel(67);
e.Row.Cells[i].Style.Add("background-image", back2);
//e.Row.Cells[i].Style.Add("width", "150px");
//e.Row.Cells[i].Style.Add("word-wrap", "break-word");
e.Row.Cells[i].Attributes.Add("align", "center");
}
}
string color = "#000000";
e.Row.Cells[0].Attributes.Add("Style", "background-color: " + color + ";");
e.Row.Cells[0].Width = Unit.Pixel(150);
e.Row.Cells[0].Height = Unit.Pixel(67);
}
if (e.Row.RowType == DataControlRowType.DataRow)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
LinkButton _singleClickButton = (LinkButton)e.Row.Cells[0].Controls[0];
string _jsSingle = ClientScript.GetPostBackClientHyperlink(_singleClickButton, "");
// Add events to each editable cell
for (int columnIndex = 2; columnIndex < e.Row.Cells.Count; columnIndex++)
{
// Add the column index as the event argument parameter
string js = _jsSingle.Insert(_jsSingle.Length - 2, columnIndex.ToString());
// Add this javascript to the onclick Attribute of the cell
e.Row.Cells[columnIndex].Attributes["onclick"] = js;
// Add a cursor style to the cells
e.Row.Cells[columnIndex].Attributes["style"] += "cursor:pointer;cursor:hand;";
}
}
}
}
Try to assign white color to the every cell and then overwrite according to conditions.
You need to use string.IsNullOrEmpty() like
if(string.IsNullOrEmpty(e.Row.Cells[i].Text))
{
e.Row.Cells[i].BackColor = Color.Blue;
e.Row.Cells[i].ForeColor = Color.White;
}
MSDN
Hope it works.

Categories

Resources