I have been playing with this issue for a couple of hours and can't seem to get it to work.
It seems to not be searching the rows?
private void searchbutton_Click(object sender, EventArgs e)
{
string searchValue = searchtextBox.Text;
int rowIndex = 0;
inkGridView.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
try
{
bool valueResulet = true;
foreach (DataGridViewRow row in inkGridView.Rows)
{
if (row.Cells[rowIndex].Value.ToString().Equals(searchValue))
{
rowIndex = row.Index;
inkGridView.Rows[rowIndex].Selected = true;
rowIndex++;
valueResulet = false;
}
}
if (valueResulet != false)
{
MessageBox.Show("Unable to find "+ searchtextBox.Text,"Not Found");
return;
}
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
}
It just always throws the error.
I made a search textbox for a dataGridView I used so perhaps this is of use to you, since the controls are quite similar. although I chose to not give a message when it can't find it. Rather then a message it turns the textbox red, also it tries to find the first occurence of the complete text. If it can't find a complete match it will try to find a match that contains the search value
private void searchart()
{
int itemrow = -1;
String searchValue = cueTextBox1.Text.ToUpper();
if (searchValue != null && searchValue != "")
{
foreach (DataGridViewRow row in dataGridView1.Rows)
{
//search for identical art
if (row.Cells[0].Value.ToString().Equals(searchValue))
{
itemrow = row.Index;
break;//stop searching if it's found
}
//search for first art that contains search value
else if (row.Cells[0].Value.ToString().Contains(searchValue) && itemrow == -1)
{
itemrow = row.Index;
}
}
//if nothing found set color red
if (itemrow == -1)
{
cueTextBox1.BackColor = Color.Red;
}
//if found set color white, select the row and go to the row
else
{
cueTextBox1.BackColor = Color.White;
dataGridView1.Rows[itemrow].Selected = true;
dataGridView1.FirstDisplayedScrollingRowIndex = itemrow;
}
}
}
I would say that unless you've set DataGridView.AllowUserToAddRows to false you are getting a null reference exception once you try to access Value.ToString() on the last row. So either set that to false or if you want to allow adding of new rows just add a check
if (row.IsNewRow) continue;
It seems to me that your if-statement is the problem. Namely row.Cells[rowIndex] returns the Cells in each row and therefore what you named rowIndex and used in the if-statement is actually column index. So you can change it to, say:
if (row.Cells[0].Value.ToString().Equals(searchValue))
to search the first column. To check all Cell columns you have to loop over them in each row.
You might also wanna look over the use of rowIndex over all, since you first assigned it to 0 and incerement it in your loop. But, then you assign it to
rowIndex = row.Index;
and proceed to increment it (but only if you found a match). I think you just got your row and column indexes mixed up/intertwined.
Edit: And i presume the thrown exception is due to there not beeing enough columns as you loop over Cells (0, 0), (1, 1), (2, 2) ... and so forth instead of looping over rows with and a specified column.
Related
Can please any one help me on this. I have developed a c# windows application which has DataGridView first column has checkboxes. if I click on first column header it selects all the row level check boxes except the first row. For selecting all row level check boxes I have an event of dataGridView1_ColumnHeaderMouseClick and the code is:
private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
foreach (DataGridViewColumn column in dataGridView1.Columns)
{
column.SortMode = DataGridViewColumnSortMode.NotSortable;
}
if (e.ColumnIndex == 0)
{
if (chek == 0)
{
try
{
for (int i = 0; i < dataGridView1.RowCount; i++)
{
string paymentValue = dataGridView1.Rows[i].Cells[18].Value.ToString();
string incmngp = dataGridView1.Rows[i].Cells[20].Value.ToString();
if (paymentValue == "N" && incmngp =="")
{
dataGridView1.Rows[i].Cells[0].Value = 1;
chek = 1;
}
}
if (chek == 1)
{
btn_update.Text = "Update";
}
}
catch (Exception ) { }
}
else if(chek==1)
{
try
{
for (int i = 0; i < dataGridView1.RowCount; i++)
{
dataGridView1.Rows[i].Cells[0].Value = 0;
chek = 0;
}
if (chek == 0)
{
btn_update.Text = "OK";
}
}
catch (Exception) { }
}
}
Note: chek is the variable declared on initialize stage
Set your Selection mode property of data grid view to ColumnHeaderSelect
and make sure all your 'Text' columns have SortMode set to NotSortable
UPDATE 2
In which case, Undo everything I ever told before and do that like this
Before you are assigning any DataTable to dataGridView1.
da.Fill(dt);
dataGridView1.DataSource = dt.DefaultView;
dataGridView1.SelectionMode = DataGridViewSelectionMode.RowHeaderSelect;
foreach(DataGridViewColumn dc in dataGridView1.Columns)
{
dc.SortMode = DataGridViewColumnSortMode.NotSortable;
}
dataGridView1.SelectionMode = DataGridViewSelectionMode.ColumnHeaderSelect;
UPDATE 3
Add an event handler for your dataGridView1's ColumnHeaderMouseClick Event
like below
Add the below code (Generic code if you want to use the same functionality for any column of check boxes)
private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
//Enter your own column index here
if(e.ColumnIndex == 0)
foreach(DataGridViewRow row in dataGridView1.Rows)
foreach (DataGridViewCell cell in row.Cells)
{
//Check if the cell type is of a CheckBoxCell
if (cell.GetType() == typeof(DataGridViewCheckBoxCell))
{
DataGridViewCheckBoxCell c = (DataGridViewCheckBoxCell)cell;
c.TrueValue = "T";
c.FalseValue = "F";
if (c.Value == c.FalseValue|| c.Value == null )
c.Value = c.TrueValue;
else
c.Value = c.FalseValue;
}
}
dataGridView1.RefreshEdit();
}
This is a very bizarre bug in Winforms. The problem more generally applies not to the first row, but to the first selected cell in any row of DataGridViewCheckBoxCell(s). You can select the CheckBox cell by clicking on the check box, or select the cell outside the check box, the behavior is the same. If you select 3 check boxes in the middle of your grid, the first of those three will freeze and not update properly. If you try to clear the selection in code, with a dataGridView1.ClearSelection() method call, it still does not work.
The correct answer is to call datagridview1.RefreshEdit() right after you change the checkbox data. You can't just call it after all changes are made. It must be made for each change in the CheckBox value.
foreach (DataGridViewRow row in Results.Rows)
{
var ck = (DataGridViewCheckBoxCell) row.Cells["check"];
ck.Value = ck.TrueValue;
Results.RefreshEdit();
}
I have a datagridview named PTable which shows a table from database. I also have a button that functions to copy the data from selected rows to the textboxes I have.
This code that I have right now copies two selected rows from the datagridview but when I only select one row or when I select more than 2 rows, it says that "Index was out of range"
What should happen is that it should copy any number of rows and not only 2 rows
private void button11_Click(object sender, EventArgs e)
{
productid.Text = PTable.SelectedRows[0].Cells[0].Value + string.Empty;
productname.Text = PTable.SelectedRows[0].Cells[1].Value + string.Empty;
unitprice.Text = PTable.SelectedRows[0].Cells[4].Value + string.Empty;
productid2.Text = PTable.SelectedRows[1].Cells[0].Value + string.Empty;
productname2.Text = PTable.SelectedRows[1].Cells[1].Value + string.Empty;
unitprice2.Text = PTable.SelectedRows[1].Cells[4].Value + string.Empty;
}
If a user have not selected two rows, your index 1 (PTable.SelectedRows[1]) is not valid, because the item is not there.
Before you can run this code, you have to check, if the user selected two rows:
if (PTable.SelectedRows.Count == 2)
{
//Your code ...
}
else
{
//Not two rows selected
}
First, make sure SelectionMode of DataGridView to FullRowSelect(Hope you have done it already)
Second, Use foreach or any looping logic to go through each selected rows.
Third, It's always better to write modular code. Write a validation method which returns TRUE or FALSE based on selection of the grid rows.
Now based on returned value you need to continue writing your business logic.
Fourth, Make sure to use NULL checks
So let's start by re-factoring the code.
private void button11_Click(object sender, EventArgs e)
{
If(IsRowOrCellSelected())
{
//loop through selected rows and pick your values.
}
}
I am just writing sample, make sure PTable is accessible.
private boolean IsRowOrCellSelected()
{
if (PTable.SelectedRows.Count > 0)
{
DataGridViewRow currentRow = PTable.SelectedRows[0];
if (currentRow.Cells.Count > 0)
{
bool rowIsEmpty = true;
foreach(DataGridViewCell cell in currentRow.Cells)
{
if(cell.Value != null)
{
rowIsEmpty = false;
break;
}
}
}
if(rowIsEmpty)
return false;
else
return true;
}
Code can be still improved.
To work with varying number of selected rows I suggest the following.
My approach is:
There may be more than 5 rows, that You have to display. First create 3 panels for the TextBoxes. I have named the one for the productids as here. Generate the textboxes from code, this way it's easier to maintain more than 5 selected rows:
// This code goes to the constructor of the class. Not in the button click
List<TextBox> productids = new List<TextBox>();
List<TextBox> productnames = new List<TextBox>();
List<TextBox> unitprices = new List<TextBox>();
for (int i = 0; i < 5; i++)
{
productids.Add(new TextBox { Top = i * 32 });
productnames.Add(new TextBox { Top = i * 32 });
unitprices.Add(new TextBox { Top = i * 32 });
here.Controls.Add(productids[i]);
here2.Controls.Add(productnames[i]);
here3.Controls.Add(unitprices[i]);
}
Than You can in the button click set the value for each selected row:
// This code goes to the button click
// first empty the Textboxes:
foreach (TextBox productid in productids)
{
productid.Text = string.Empty;
}
foreach (TextBox productname in productnames)
{
productname.Text = string.Empty;
}
foreach (TextBox unitprice in unitprices)
{
unitprice.Text = string.Empty;
}
for (int i = 0; i < PTable.SelectedRows.Count; i++)
{
productids[i].Text = PTable.SelectedRows[i].Cells[0].Value.ToString();
productnames[i].Text = PTable.SelectedRows[i].Cells[1].Value.ToString();
// or better... Name the columns
// unitprices[i].Text = PTable.SelectedRows[i].Cells["unitPrices"].Value.ToString();
unitprices[i].Text = PTable.SelectedRows[i].Cells[4].Value.ToString();
}
I have a datagridview where one of the columns is a color column. I want to ensure the user enters a valid color, otherwise leave the cell blank.
When the cell is starting from blank, the following code gives me a null reference exception. Fyi, I am doing this in the CellLeave event.
Answer I had to move the code to the CellFormatting event. For some reason, the value at the cell does not get updated until a certain unknown point. For my check, I need to do it before something I was doing in the CellFormatting event. Moving the code there fixed my problem.
private void dataGridView1_CellFormatting(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex.Equals(2))
{
Regex test = new Regex("[0-255],[0-255],[0-255]");
Match m = test.Match(this.dataGridView1.CurrentCell.Value.ToString());
if(!m.Success)
{
this.dataGridView1.CurrentCell.Value = "";
}
}
}
To validate a string you could use this method:
private static bool IsValidColorString(string input)
{
if (String.IsNullOrEmpty(input))
return false;
string[] parts = input.Split(',');
if (parts.Length != 3)
return false;
foreach (string part in parts)
{
int val;
if (!int.TryParse(part, out val) || val < 0 || val > 255)
return false;
}
return true;
}
The best place to use it I believe is the DataGridView.CellParsing event handler:
private void dataGridView1_CellParsing(object sender, DataGridViewCellParsingEventArgs e)
{
if (e.Value == null || e.ColumnIndex != 2) // Skip empty cells and columns except #2
return;
string input = e.Value.ToString();
if (!IsValidColorString(input))
e.Value = String.Empty; // An updated cells's value is set back to the `e.Value`
}
An updated cells's value is set back to the e.Value instead of the DataGridView.CurrentCell.Value.
Try this for your match:
Match m = test.Match((this.dataGridView1.CurrentCell.Value ?? "").ToString());
This will replace a null value with an empty string when matching.
Do you perhaps need to check to see if there is a value within the cell before you try and match a Regex?
if (e.ColumnIndex.Equals(2))
{
if(this.dataGridView1.CurrentCell.Value != null)
{
...
CurrentCell.Value.ToString()
Causing the error..
CurrentCell.value=null
null value can't cast using the tostring() method,that's why you are getting ther null reference exception.
try this..
string val="";
if(dataGridView1.CurrentCell.Value==null)
{
val=""
}
els
else
{
val=convert.tostring(dataGridView1.CurrentCell.value);
}
Match m = test.Match(val);
if(!m.Success)
{
this.dataGridView1.CurrentCell.Value = "";
}
This is the code on my button so far:
DateTime thisDay = DateTime.Today;
dataGridView1.Rows.Add(thisDay.ToString("d"));
How can I let it check if "todays" date is already written to a row and overwrite it (of course it doesnt make much sense here, but I will add more cells which also should be overwrite in that case) instead of making a new row with the same date?
Thanks
You can try this way :
string thisDay = DateTime.Today.ToString("d");
var duplicateRow = (from DataGridViewRow row in dataGridView1.Rows
where (string)row.Cells["columnName"].Value == thisDay
select row).FirstOrDefault();
if (duplicateRow != null)
{
//duplicate row found, update it's columns value
duplicateRow.Cells["columnName"].Value = thisDay;
}
else
{
//duplicate row doesn't exists, add new row here
}
That uses linq to select a row having particular column value equal current date. When no row match the criteria, .FirstOrDefault() will return null, else it will return first matched row.
private void DataGridView_CellFormatting(object sender,
System.Windows.Forms.DataGridViewCellFormattingEventArgs e)
{
// Check if this is in the column you want.
if (dataGridView1.Columns[e.ColumnIndex].Name == "ColumnName")
{
// Check if the value is large enough to flag.
if (Convert.ToInt32(e.Value).Tostring == "HIGH")
{
//Do what you want with the cell lets change color
e.CellStyle.ForeColor = Color.Red;
e.CellStyle.BackColor = Color.Yellow;
e.CellStyle.Font =
new Font(dataGridView1.DefaultCellStyle.Font, FontStyle.Bold);
}
}
}
Using MS Visual Studio 2012, Telerik, C#.ASP.NET.
The logic I need is as follows:
If a columns data on all rows is null then hide the column
Basically if a column has 3 rows of data, if there all null then dont bother displaying that column, however if there is a value in 1 of them, then show the column.
been playing around:
foreach (GridColumn columns in dgvUserResults.Columns)
{
if (columns != null)
{
columns.Visible = false;
}
else
{
columns.Visible = true;
}
}
code doesn't work of course doesnt iterate through the foreach loop just skips it. Although not bothered about that even if it did iterate through I need a way to check if all column[name] rows are null. There a nice Telerik one liner?
Please try with below code snippet.
Using UniqueName
protected void RadGrid1_PreRender(object sender, EventArgs e)
{
foreach (GridColumn column in RadGrid1.MasterTableView.Columns)
{
// If you used ClientSelectColumn then below code is not worked For that you have to put condition
//if(column.ColumnType == "GridBoundColumn")
int TotalNullRecords = (from item in RadGrid1.MasterTableView.Items.Cast<GridDataItem>()
where string.IsNullOrWhiteSpace(item[column.UniqueName].Text) ||
item[column.UniqueName].Text == " "
select item).ToList().Count;
if (TotalNullRecords == RadGrid1.MasterTableView.Items.Count)
{
RadGrid1.MasterTableView.Columns.FindByUniqueName(column.UniqueName).Visible = false;
}
}
}
By Using Index
protected void RadGrid1_PreRender(object sender, EventArgs e)
{
foreach (GridColumn column in RadGrid1.MasterTableView.Columns)
{
// If you used ClientSelectColumn then below code is not worked For that you have to put condition
//if(column.ColumnType == "GridBoundColumn")
int TotalNullRecords = (from item in RadGrid1.MasterTableView.Items.Cast<GridDataItem>()
where string.IsNullOrWhiteSpace(item[column.UniqueName].Text) ||
item[column.UniqueName].Text == " "
select item).ToList().Count;
if (TotalNullRecords == RadGrid1.MasterTableView.Items.Count)
{
column.Visible = false;
}
}
}
For col = 0 To myRadGridView.ColumnCount
Dim mustKeepColumn As Boolean = False
For Each r In myRadGridView.Rows
If Not String.IsNullOrEmpty(r.Cells(col).Value.ToString) Then
mustKeepColumn = True
Exit For
End If
Next
If Not mustKeepColumn Then
myRadGridView.Columns(col).IsVisible = False
End If
Next