I wanted to create a simple program that looks trough each row of a dataGridView on a specific cell.
I got it to work but if the string that I search for isn't found it gives back null. Which screws it up. Here is the code:
string targetSearch = textBox2.Text;
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
foreach(DataGridViewRow row in dataGridView1.Rows)
{
if (row.Cells[0].Value.ToString().Equals(targetSearch))
{
row.Selected = true;
break;
}
}
These solutions works for me.
Sample UI
Validate if the value is null.
private void btnSearch_Click(object sender, EventArgs e)
{
string targetSearch = txtSearch.Text.Trim();
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
foreach(DataGridViewRow row in dataGridView1.Rows) {
if (row.cells[0].value == null)
continue;
if(row.cells[0].value.Tostring().Trim().Equals(targetSearch)) {
row.Selected = true;
break;
}
}
}
Handle the NullReference Exception
private void btnSearch_Click(object sender, EventArgs e)
{
string targetSearch = txtSearch.Text.Trim();
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
try
{
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.Cells[0].Value.ToString().Equals(targetSearch))
{
row.Selected = true;
break;
}
}
}
catch (NullReferenceException ex) { }
}
You are converting null value to string, which gives System.NullReferenceException.
string targetSearch = textBox2.Text;
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
foreach(DataGridViewRow row in dataGridView1.Rows)
{
if (row.Cells[0].Value == null) continue; //add this
if (row.Cells[0].Value.ToString().Equals(targetSearch))
{
row.Selected = true;
break;
}
}
There are two things you can try:
Either Set "AllowUserstoAddRows" to False
or
Put the foreach loop in a Try catch block in order to handle the NullReference exception
Related
This question already has answers here:
Unable To set row visible false of a datagridview
(7 answers)
Closed 5 years ago.
I'm trying to make my datagridview searchable, but I can't seem to get the hang of it. I've tried googling my way to the solution, whereas I found the following:
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.Cells[0].Value.ToString().ToLower().Contains(searchTextBox.Text.ToLower()) && row.Cells[0] != null)
{
row.Visible = true;
}
else
{
row.Visible = false;
}
}
The above code is linked to a button on a form, not a lot to show there. When I enter a string into the textbox, and click the button, I get the following exception:
Row associated with the currency manager's position cannot be made invisible.
I have no idea how to deal with this exception, I've tried various changes, but nothing has helped.
Just to give you an idea, this is my form's code (I only have 1 form):
namespace IntegratorReader
{
public partial class start : Form
{
DataTable dt = new DataTable();
public start()
{
InitializeComponent();
}
private void bOpenFileDialog_Click(object sender, EventArgs e)
{
OpenFileDialog theDialog = new OpenFileDialog();
theDialog.Title = "Open Text File";
theDialog.Filter = "TXT files|*.txt";
theDialog.InitialDirectory = #"C:\";
if (theDialog.ShowDialog() == DialogResult.OK)
{
try
{
if ((theDialog.OpenFile()) != null)
{
string fullPath = theDialog.FileName;
string fileName = theDialog.SafeFileName;
MessageBox.Show(fullPath);
fillGridView(fullPath);
}
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
}
private void fillGridView (string path)
{
var regex = new Regex("\\\"(.*?)\\\"");
System.IO.StreamReader file = new System.IO.StreamReader(path);
string[] columnnames = file.ReadLine().Split(',');
foreach (string c in columnnames)
{
dt.Columns.Add(c);
}
string newline;
while ((newline = file.ReadLine()) != null)
{
newline = regex.Replace(newline, m => m.Value.Replace(',', ' '));
DataRow dr = dt.NewRow();
string[] values = newline.Split(',');
for (int i = 0; i < values.Length; i++)
{
string v = values[i];
v = v.Replace("\"", "");
dr[i] = v;
}
dt.Rows.Add(dr);
}
file.Close();
dataGridView1.DataSource = dt;
}
private void searchButton_Click(object sender, EventArgs e)
{
try
{
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.Cells[0].Value.ToString().ToLower().Contains(searchTextBox.Text.ToLower()) && row.Cells[0] != null)
{
row.Visible = true;
}
else
{
row.Visible = false;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
Short example:
I open a .txt file with a lot of rows, whereas I take the first row and base the columns off of that. I then proceed to read the lines and put them into their columns based off of the "," splitter. I realise that this could've been done with a CSV reader of some sort, but I need this to work. This is a work related thing, so I can't give you the exact .txt file, but it generally looks like this, just with more rows and more columns:
"customerID","CustomerName"
"1","Bob"
"2","Dennis"
"3","Richard"
"4","Fernando"
You get the general idea...
Now, my question is, am I completely in the wrong about how to search in a datagridview, or is it simply a smaller issue that I'm overseeing?
Is there a better way to search in a datagridview, if yes, how?
For reference, this is how the form looks:
Question is very much duplicate of this:
There two issues with your code, 1- It does not perform check for empty row(last row) and it does not suspend currencyManager while hiding a row.
To fix, replace your searchButton_Click code with following:
private void searchButton_Click(object sender, EventArgs e)
{
try
{
foreach (DataGridViewRow row in dataGridView1.Rows)
{
CurrencyManager currencyManager1 = (CurrencyManager)BindingContext[dataGridView1.DataSource];
currencyManager1.SuspendBinding();
if (row.IsNewRow)
continue;
if (row.Cells[0].Value.ToString().ToLower().Contains(searchTextBox.Text.ToLower()) )
{
row.Visible = true;
}
else
{
row.Visible = false;
}
currencyManager1.ResumeBinding();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
**Answer Update **
Another option is to set the current cell to null before deleting OR hiding a row as the error tells that "
Row is associated with the currency Manager
".
if(dataGridView1.CurrentCell!=null)
dataGridView1.CurrentCell = null;
row.Visible = true;//row.Visible = false
I am developing an application that reads RFID's in the serial port. I use a timer to keep scaning until the user clicks a button.
When the scanner find a new RFID, I insert the info in a DataGridView, if the RFID is already in the DataGridView I paint the row with green color and if a RFID in the DataGridView is not anymore in the scanner range I paint it with white color.
My problem is that with small lapses of time the RFID is inserted more than once.
I thought that it was for the threads in the timer, so I put a lock inside, but if I try to scan in lapses smallers than 200 ms the problem still happening.
Is there a way to improve the code?
void tmrRepeatedScan_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
try
{
lock (thisLock)
{
var detectedTags = serialPort.Scan(true, false, true, false);
foreach (var tag in detectedTags)
{
bool tagFound = false;
string TID = Regex.Replace(Conversions.ByteToHexadecimal(tag.GetTagId()), "(.{2})(?!$)", "$0-");
string EPC = Regex.Replace(Conversions.ByteToHexadecimal(tag.GetEpc()), "(.{2})(?!$)", "$0-");
if (!tagsReaded.Contains(TID))
{
tagsReaded.Add(TID);
}
foreach (DataGridViewRow row in dgvTags.Rows)
{
if (row.Cells[0].Value.ToString().Equals(TID))
{
row.DefaultCellStyle.BackColor = Color.LightGreen;
tagFound = true;
break;
}
}
if (!tagFound)
{
dgvTags.BeginInvoke(new InvokeDelegate(() => AddRow(TID, EPC)));
}
}
}
foreach (DataGridViewRow row in dgvTags.Rows)
{
if (!tagsReaded.Contains(row.Cells[0].Value.ToString()))
{
row.DefaultCellStyle.BackColor = Color.White;
}
}
}
catch (Exception ex)
{
foreach (DataGridViewRow row in dgvTags.Rows)
{
row.DefaultCellStyle.BackColor = Color.White;
}
}
}
Sorry if my english is not very good.
You can switch it back to BeginInvoke but you need to include a check to see if your tag exists in tagsReaded before doing AddRow. Try this:
void tmrRepeatedScan_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
try
{
lock (thisLock)
{
var detectedTags = serialPort.Scan(true, false, true, false);
foreach (var tag in detectedTags)
{
bool tagFound = false;
string TID = Regex.Replace(Conversions.ByteToHexadecimal(tag.GetTagId()), "(.{2})(?!$)", "$0-");
string EPC = Regex.Replace(Conversions.ByteToHexadecimal(tag.GetEpc()), "(.{2})(?!$)", "$0-");
foreach (DataGridViewRow row in dgvTags.Rows)
{
if (row.Cells[0].Value.ToString().Equals(TID))
{
row.DefaultCellStyle.BackColor = Color.LightGreen;
tagFound = true;
break;
}
}
bool isNewTag = !tagsReaded.Contains(TID);
if (!tagFound && isNewTag )
{
dgvTags.BeginInvoke(new InvokeDelegate(() => AddRow(TID, EPC)));
}
if (newTag)
{
tagsReaded.Add(TID);
}
}
}
foreach (DataGridViewRow row in dgvTags.Rows)
{
if (!tagsReaded.Contains(row.Cells[0].Value.ToString()))
{
row.DefaultCellStyle.BackColor = Color.White;
}
}
}
catch (Exception ex)
{
foreach (DataGridViewRow row in dgvTags.Rows)
{
row.DefaultCellStyle.BackColor = Color.White;
}
}
}
I want to search for a string value in column ProductName in dataGridView1 then I want to delete or hide any other value in dataGridView1
Search value is typed in textBox1
I tried this
string searchValue = textBox1.Text;
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
try
{
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.Cells[2].Value.ToString().Equals(searchValue))
{
row.Selected = true;
break;
}
}
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
but I get object reference not set to an instance of an object
In order to be able to manipulate your data(deleting rows, etc), you are going to have to bind your dataGridView to a DataTable or a DataSet and then manipulate your records through the DataSet/DataTable. This would let you reflect the changes in you dataGridView.
Lets try, If I understand your problem.
string searchValue = textBox1.Text;
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
try
{
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.Cells[2].Value.ToString().Equals(searchValue))
{
row.Selected = true;
}
else
{
dataGridView1.Rows.RemoveAt(row.Index); //Remove
}
}
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
i have a question regarding with this code, i use a bindingsource to show the data and this code only select the row when im searching in datagridview. i want to know how can i filter the data im searching.
private void button1_Click(object sender, EventArgs e)
{
string searchValue = textBox1.Text;
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
try
{
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.Cells[2].Value.ToString().Equals(searchValue))
{
row.Selected = true;
break;
}
}
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
}
if you want to display only the filtered rows use BindingSource.Filter property.
Here is a good sample in MSDN
bindingSource.Filter = "columnname = 'value'";
private void button1_Click(object sender, EventArgs e)
{
string searchValue = textBox1.Text;
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
bindingSource.Filter = string.Format("{0} = '{1}'","YourColumnName", searchValue );
//here you can do selection if you need
}
To remove filter use the following
bindingSource.RemoveFilter();
or
bindingSource.Filter = null;
Without changing that much your code, you could set the row.Visible property to false instead of just changing row.Selected. Anyway, the answer above is more performant and clean, you should try that.
I want the user to be able to search for a number in a column in the DataGridView (dgv). The dgv can hold many records. Each record has a Project Number. So I want the user to be able to search for a project number in column Project Number. The columns I have are: ProjectID(not visible); Image(no headertext); Project Number; Project Name; Company; Contact.
Here is my code:
private void btnSearch_Click(object sender, EventArgs e)
{
string searchValue = textBox1.Text;
int rowIndex = -1;
dgvProjects.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
try
{
foreach (DataGridViewRow row in dgvProjects.Rows)
{
if (row.Cells[row.Index].Value.ToString().Equals(searchValue))
{
rowIndex = row.Index;
dgvProjects.Rows[row.Index].Selected = true;
break;
}
}
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
}
Problem #1: What it does so far: The user types the project number in TextBox1. When he/she clicks the button, the code searches for this string in the rows, and when found the project number, that row gets selected. It works fine, but only once. When I want to search for an other project number, nothing happens.
Problem #2: I think this can be done in a better way, by searching the values for column Project Name only. But how should I do this properly?
The code I used to search comes from this answer
Why you are using row.Cells[row.Index]. You need to specify index of column you want to search (Problem #2). For example, you need to change row.Cells[row.Index] to row.Cells[2] where 2 is index of your column:
private void btnSearch_Click(object sender, EventArgs e)
{
string searchValue = textBox1.Text;
dgvProjects.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
try
{
foreach (DataGridViewRow row in dgvProjects.Rows)
{
if (row.Cells[2].Value.ToString().Equals(searchValue))
{
row.Selected = true;
break;
}
}
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
}
Why don't you build a DataTable first then assign it to the DataGridView as DataSource:
DataTable table4DataSource=new DataTable();
table4DataSource.Columns.Add("col00");
table4DataSource.Columns.Add("col01");
table4DataSource.Columns.Add("col02");
...
(add your rows, manually, in a circle or via a DataReader from a database table)
(assign the datasource)
dtGrdViewGrid.DataSource = table4DataSource;
and then use:
(dtGrdViewGrid.DataSource as DataTable).DefaultView.RowFilter = "col00 = '" + textBoxSearch.Text+ "'";
dtGrdViewGrid.Refresh();
You can even put this piece of code within your textbox_textchange event and your filtered values will be showing as you write.
It's better also to separate your logic in another method, or maybe in another class.
This method will help you retreive the DataGridViewCell object in which the text was found.
/// <summary>
/// Check if a given text exists in the given DataGridView at a given column index
/// </summary>
/// <param name="searchText"></param>
/// <param name="dataGridView"></param>
/// <param name="columnIndex"></param>
/// <returns>The cell in which the searchText was found</returns>
private DataGridViewCell GetCellWhereTextExistsInGridView(string searchText, DataGridView dataGridView, int columnIndex)
{
DataGridViewCell cellWhereTextIsMet = null;
// For every row in the grid (obviously)
foreach (DataGridViewRow row in dataGridView.Rows)
{
// I did not test this case, but cell.Value is an object, and objects can be null
// So check if the cell is null before using .ToString()
if (row.Cells[columnIndex].Value != null && searchText == row.Cells[columnIndex].Value.ToString())
{
// the searchText is equals to the text in this cell.
cellWhereTextIsMet = row.Cells[columnIndex];
break;
}
}
return cellWhereTextIsMet;
}
private void button_click(object sender, EventArgs e)
{
DataGridViewCell cell = GetCellWhereTextExistsInGridView(textBox1.Text, myGridView, 2);
if (cell != null)
{
// Value exists in the grid
// you can do extra stuff on the cell
cell.Style = new DataGridViewCellStyle { ForeColor = Color.Red };
}
else
{
// Value does not exist in the grid
}
}
// This is the exact code for search facility in datagridview.
private void buttonSearch_Click(object sender, EventArgs e)
{
string searchValue=textBoxSearch.Text;
int rowIndex = 1; //this one is depending on the position of cell or column
//string first_row_data=dataGridView1.Rows[0].Cells[0].Value.ToString() ;
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
try
{
bool valueResulet = true;
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.Cells[rowIndex].Value.ToString().Equals(searchValue))
{
rowIndex = row.Index;
dataGridView1.Rows[rowIndex].Selected = true;
rowIndex++;
valueResulet = false;
}
}
if (valueResulet != false)
{
MessageBox.Show("Record is not avalable for this Name"+textBoxSearch.Text,"Not Found");
return;
}
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
}
Filter the data directly from DataTable or Dataset:
"MyTable".DefaultView.RowFilter = "<DataTable Field> LIKE '%" + textBox1.Text + "%'";
this.dataGridView1.DataSource = "MyTable".DefaultView;
Use this code on event KeyUp of Textbox, replace "MyTable" for you table name or dataset, replace for the field where you want make the search.
"MyTable".DefaultView.RowFilter = " LIKE '%" + textBox1.Text + "%'";
this.dataGridView1.DataSource = "MyTable".DefaultView;
How about the relation to the database connections and the Datatable? And how should i set the DefaultView correct?
I use this code to get the data out:
con = new System.Data.SqlServerCe.SqlCeConnection();
con.ConnectionString = "Data Source=C:\\Users\\mhadj\\Documents\\Visual Studio 2015\\Projects\\data_base_test_2\\Sample.sdf";
con.Open();
DataTable dt = new DataTable();
adapt = new System.Data.SqlServerCe.SqlCeDataAdapter("select * from tbl_Record", con);
adapt.Fill(dt);
dataGridView1.DataSource = dt;
con.Close();
private void btnSearch_Click(object sender, EventArgs e)
{
try
{
string searchValue = txtSearch.Text;
string colName = dataGridView1.Columns[1].Name;//Column Number of Search
((DataTable)dataGridView1.DataSource).DefaultView.RowFilter = string.Format(colName+" like '%{0}%'", searchValue.Trim().Replace("'", "''"));
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
}
private void txtSearch_TextChanged(object sender, EventArgs e)
{
btnSearch_Click(null,null);
}
private void txtSearch_TextChanged(object sender, EventArgs e)
{
string searchValue = txtSearch.Text;
for (var i = 0; i <= dgvList.RowCount; i++)
{
for (var j = 0; j <= dgvList.ColumnCount; j++)
{
if ((dgvList.Item(j, i).FormattedValue.ToString.ToLower).ToString.Contains(searchValue.ToString.ToLower))
{
Console.Writeline("found");
dgvList.Item(j, i).Selected = true;
return;
}
}
}
}
This method will search all rows and cells in the DataGridView, If result is true then select the row.
I'm can solve it simply:
public static int SearchDGV(DataGridView dgv, string SearchValue, string ColName)
{
foreach (DataGridViewRow Row in dgv.Rows)
{
if (Row.Cells[ColName].Value.ToString().Equals(SearchValue))
return Row.Index;
}
return -1;
}
private void textBox3_TextChanged(object sender, EventArgs e)
{
DataView dv = ds.Tables["todo"].DefaultView;
dv.RowFilter = "topic LIKE '" + textBox3.Text + "%'";
dataGridView1.DataSource = dv;
}