In my application, I have a datagridview. For each column, there is a button. If clicked, I take the column index and now want to add a user enterd value at the first (bottom or top doesn't matter) free cell of that column. If there is no empty cell, I want to create one.
I tried looping through all rows, getting the cell values and checking if they are empty.
string data = "%VALUE%";
int rowIndex = -1;
foreach (DataGridViewRow row in dataGridViewTasks.Rows)
{
data = (string) row.Cells[columnIndex].Value;
if (string.IsNullOrWhiteSpace(data))
{
rowIndex = row.Index;
break;
}
else if (row.Cells[columnIndex].RowIndex == dataGridViewTasks.Rows.Count - 1)
{
rowIndex = dataGridViewTasks.Rows.Add();
break;
}
}
if (string.IsNullOrWhiteSpace(data) && rowIndex > -1)
{
dataGridViewTasks[columnIndex, rowIndex].Value = task.name;
}
Problem with this solution is:
If for example row 1 and 2 of column A are filled, a new value in column B is added in row 3. So that is not what I want.
If I understand you correctly, it`s should work.
Try it:
private void Button1_Click(object sender, EventArgs e)
{
var columnIndex = 1;
var dataGrid = new DataGridView();
var index = GetFirstEmptyCellByColumnIndex(dataGrid, columnIndex);
dataGrid[columnIndex, index].Value = "new value";
}
private int GetFirstEmptyCellByColumnIndex(DataGridView dataGrid, int columnIndex)
{
var index = -1;
foreach (DataGridViewRow row in dataGrid.Rows)
{
if (string.IsNullOrEmpty((string)row.Cells[columnIndex].Value))
{
index = row.Index;
break;
}
}
return index != -1
? index
: dataGrid.Rows.Add();
}
Related
I have some text and a datagridview with 5 columns. How can I find this text in the first column and get values from other columns in the same row?
I think the code lines will give you the datagridview row index for the value:
String searchValue = "somestring";
int rowIndex = -1;
foreach(DataGridViewRow row in DataGridView1.Rows)
{
if(row.Cells[1].Value.ToString().Equals(searchValue))
{
rowIndex = row.Index;
break;
}
}
then you can do:
dataGridView1.Rows[rowIndex].Selected = true;
It would be :
List<string> Values = new List<string>();
foreach (DataRow row in YourDataTable.Rows)
{
if (row["firstColumn"].ToString() == yourText)
{
Values.Add(row["firstColumn"].ToString());
Values.Add(row["secondColumn"].ToString());
Values.Add(row["thirdColumn"].ToString());
Values.Add(row["fourthColumn"].ToString());
Values.Add(row["fifthColumn"].ToString());
}
}
Table1 Fig.
Name | Marks
Pritam | 80
Aruna | 85
Uttaran | 90
Total | 255
DataTable dtStudentInfo = table1;
dataGridView1.DataSource = dtStudentInfo;
After Clicking on the column header name datagridview sort in ascending order of students' name. But I want the Total row always stays at the last of list.
I want to know if there is any way by which I can remove the last row from the list which will be sorted. If this is not possible then suggest any way by which i can get the result. NOTE: I don't want any external button to sort the list.
I've solved the problem by the following way:
DataGridViewRow dgRowTotalCount;
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex == -1)
{
dgRowTotalCount = (DataGridViewRow)dataGridView1.Rows[((DataGridView)sender).Rows.Count - 1].Clone();
for (Int32 index = 0; index < ((DataGridView)sender).Rows[((DataGridView)sender).Rows.Count - 1].Cells.Count; index++)
{
dgRowTotalCount.Cells[index].Value = ((DataGridView)sender).Rows[((DataGridView)sender).Rows.Count - 1].Cells[index].Value;
}
((DataGridView)sender).Rows.RemoveAt(((DataGridView)sender).Rows.Count - 1);
}
}
private void dataGridView1_Sorted(object sender, EventArgs e)
{
DataTable dtDGVCopy = new DataTable();
foreach (DataGridViewColumn col in dataGridView1.Columns)
{
dtDGVCopy.Columns.Add(col.Name);
}
foreach (DataGridViewRow row in dataGridView1.Rows)
{
DataRow dRow = dtDGVCopy.NewRow();
foreach (DataGridViewCell cell in row.Cells)
{
dRow[cell.ColumnIndex] = cell.Value;
}
dtDGVCopy.Rows.Add(dRow);
}
dtDGVCopy.Rows.Add();
for (Int32 i = 0; i < dgRowTotalCount.Cells.Count - 1; i++)
{
dtDGVCopy.Rows[dtDGVCopy.Rows.Count-1][i] = dgRowTotalCount.Cells[i].Value;
}
dataGridView1.DataSource = null;
dataGridView1.DataSource = dtDGVCopy;
}
But its not smooth as it was before. If there is any way by which i can make it's performance as it was before that would be great.
I know this is an old question, but here is a solution I've come up with. Use the SortCompare event on the grid to override the sorting for a specific row:
private void dgvData_SortCompare(object sender, DataGridViewSortCompareEventArgs e)
{
if (dgvData.Rows[e.RowIndex1].Cells[0].Value.ToString() == "Total" ||
dgvData.Rows[e.RowIndex2].Cells[0].Value.ToString() == "Total")
{
if (dgvData.SortOrder == SortOrder.Ascending)
{
e.SortResult = -1;
}
else
{
e.SortResult = 1;
}
e.Handled = true;
}
}
Now any row that has "Total" in the first column will always sort to the end of the grid.
(If you allow columns to be reordered then you'll need to figure out how to check the correct column)
How do I highlight a datagrid row based off the value in textbox2?
Ultimately when a matching value is found in Column 2 the QTY field (column 3) on that corresponding row will need change by -1 for each QR Code scanned by the End user. Once the QTY value reaches 0 the the row will need to be highlighted Green.
I can't just get it to work have tried a few different ways of writing the foreach section but no luck
My code is as below:
private void textBox2_KeyPress(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
iCBOMHDataGridView.DataSource = iCBOMHBindingSource;
string input = textBox2.Text;
string output = "";
textBox2.Text = Regex.Replace(input, #"^\d{4}|[A-z]{2}[0-9]{5},|,|,|\d{|[0-9]{4}/....|\d{1,}\/\d{2,2}\/\d{4}|\s.........|\s|,|,|,|\d*?.$|[*?:/]\n|\r|\r\n", output);
foreach (DataGridViewRow row in iCBOMHDataGridView.Rows)
{
if ((string)row.Cells[2].Value == textBox2.Text)
{
row.Selected = true;
}
else
{
row.Selected = false;
MessageBox.Show("Part Number doesn't match");
}
}
}
}
You can do a loop inside all cells of that row and set the cell Style property. You can create different styles for non-selected and selected rows, then apply these styles as necessary.
Example:
DataGridViewCellStyle selectedStyle = new DataGridViewCellStyle();
selectedStyle.BackColor = Color.LemonChiffon;
selectedStyle.ForeColor = Color.OrangeRed;
DataGridViewCellStyle defaultStyle = new DataGridViewCellStyle();
defaultStyle.BackColor = System.Drawing.Color.White;
defaultStyle.ForeColor = Control.DefaultForeColor;
foreach (DataGridViewRow row in iCBOMHDataGridView.Rows)
{
if ((string)row.Cells[2].Value == textBox2.Text)
{
row.Selected = true;
if(Decimal.Parse(row.Cells[3].Value.ToString()) > 0)
row.Cells[2].Value = Decimal.Parse(row.Cells[2].Value.ToString()) - 1;
}
if (Decimal.Parse(row.Cells[3].Value.ToString()) <= 0)
{
foreach (DataGridViewCell col in row.Cells.AsParallel())
col.Style = selectedStyle;
}
else
{
foreach (DataGridViewCell col in row.Cells.AsParallel())
col.Style = defaultStyle;
}
}
If you do not want to loop through the cells, you can simply change the DataRow.DefaultCellStyle property of each row. But this will limit your customization options.
I have one or two datagridviews in seven different tabs. I have a search box that worked fine when just searching the datagridview in the current selected tab, however searching across multiple tabs has proved to be a problem. The first time the search is used, nothing happens. After that, when the substring that's being searched for is found, the correct tab is shown, however the row containing the substring is not highlighted. If I search again without changing tab pages, the correct row will be highlighted... Thank you in advance for the help! Here are my methods:
private void searchBox_KeyDown(object sender, KeyEventArgs e)
{
// Declare DGV
DataGridView DGV = null;
bool isFound = false;
int tabIndex = -1;
// When a key is pressed and it's the enter key...
if (e.KeyCode == Keys.Enter)
{
// Loop through all tab pages
for (int i = 0; i < tabs.TabCount; i++)
{
// Loop through all controls in the selected tab
foreach (Control c in tabs.TabPages[i].Controls)
{
// if the control is a datagridview, cast it as a datagridview,
// and set DGV equal to it
if (c is DataGridView)
{
DGV = (DataGridView)c;
string name = DGV.Name;
// Pass in DGV to Search() to search all cells within it for
// the term in the searchbox
isFound = Search(DGV);
}
if (isFound)
tabIndex = i;
}
}
if (tabIndex >= 0)
{
tabs.SelectTab(tabIndex);
tabs.SelectedTab.Show();
highLightSearchRows();
}
}
}
This is my Search method:
private bool Search(DataGridView dataGrid)
{
int i, j;
bool retval = false;
// Makes sure searchBox contains text before searching
if (searchBox.TextLength <= 0)
return false;
string searchBoxText = searchBox.Text, sub1 = searchBox.Text.Substring(1);
// Doesn't accept an empty string as a valid search parameter
if (searchBoxText == "")
return false;
string searchForText = searchBoxText;
// Starts looping from the bottom of the grid up
// This makes FirstDisplayedScrollingRowIndex show the uppermost match in the grid
for (i = dataGrid.Rows.Count - 1; i >= 0; i--)
{
// If any cells contain the search string, they are highlighted
if (dataGrid.Rows[i].Cells.OfType<DataGridViewCell>()
.Any(cell => ((dynamic)cell.Value).Contains(searchForText)))
retval = true;
// Deselect all rows in all datagrids in order for other rows to
// be programmatically selected
dataGrid.Rows[i].Selected = false;
}
return retval;
}
And the highlight rows method:
private void highLightSearchRows()
{
DataGridView DGV = null;
int rowIndex = -2;
foreach (Control c in tabs.SelectedTab.Controls)
{
// if the control is a datagridview, cast it as a datagridview,
// and set DGV equal to it
if (c is DataGridView)
{
DGV = (DataGridView)c;
string name = DGV.Name;
foreach (DataGridViewRow row in DGV.Rows)
{
// If any cells contain the search string, they are highlighted
if (row.Cells.OfType<DataGridViewCell>()
.Any(cell => ((dynamic)cell.Value).Contains(searchBox.Text)))
{
// Makes selected row the top row in the view
rowIndex = row.Index;
row.Selected = true;
DGV.FirstDisplayedScrollingRowIndex = rowIndex;
}
if (rowIndex >= 0)
{
// Select the matching row
row.Selected = true;
rowIndex = -2;
}
}
}
}
}
I have the following code:
int countRows = dataGridView3.SelectedRows.Count;
int rowIndex = 0;
foreach (DataGridViewRow row in dataGridView3.SelectedRows)
{
int selectedRowIndex = dataGridView3.SelectedCells[rowIndex].RowIndex;
DataGridViewRow selectedRow = dataGridView3.Rows[selectedRowIndex];
capacity = Convert.ToInt32(selectedRow.Cells["Cust_Number"].Value);
capStore.Add(capacity);
rowIndex++;
}
I try to go through each selected row in my DataGridView and store the value from the column "Cust_Number" into an ArrayList, so that I can change it later. Somehow he just grabs the second row each time I iterate and I have the same value in my ArrayList duplicated. What is wrong here?
I would try the following code :
if(dataGridView3.SelectedRows != null && dataGridView3.SelectedRows.Count > 0)
{
foreach (DataGridViewRow dgvr in dataGridView3.SelectedRows)
{
int tempVal = 0;
if(dgvr.Cells["Cust_Number"].Value != null && int.TryParse(dgvr.Cells["Cust_Number"].Value.ToString(), out tempVal))
{
capStore.Add(tempVal);
}
}
}
This is simpler and safer.