I've created a software with a datagridview. It can save all data from datagridview.But the problem is data, if a user don't insert data in one cell, software will crash. How i can verify this ? I save dgv content with this code :
//Write in file
StreamWriter ecriture = new StreamWriter(tes, true);
for (int i = 0; i < dataGridView1.Rows.Count-1; i++)
{
for (int j = 0; j < dataGridView1.Columns.Count; j++)
{
ecriture.Write("\t"+dataGridView1.Rows[i].Cells[j].Value.ToString()+"\t"+"|");
}
ecriture.WriteLine("");
}
ecriture.Close();
I hope you can help me :)
Thanks from France
You should create a data model, just a class that contains properties which are corresponding to your data grid columns.
public class MyModel {
public string prop1 {get;set;}
}
Then bind BindingList<MyModel> to your grid like that:
dgv.DataSource = myList;
And then use that list of objects to obtain data fro grid as oppose to reading text or value from cells.
You can always check if cells has VALUES etc, but that not very Object Oriented approach and also very hard to maintain as code change when you want to reorder columns.
Something to read:
https://msdn.microsoft.com/en-us/library/y0wfd4yz(v=vs.110).aspx
Binding List<T> to DataGridView in WinForm
If you still want to go your way, make sure that all elements of that chain are not nulls.
dataGridView1.Rows[i].Cells[j].Value.ToString()
If Row with that index doesn't exist, there is IndexOutOfRangeException, same for column with given index. If cell exists but is empty, its Value is NULL and then you get NullReferenceException because you can't do ToString on null object.
Related
I have seen many question relevant to that here but none of them make any sense to me. So anyone who could help me out here.
First of all i am scraping data from Amazon site and saving the data in this DataGridView
dataGridViewScraping Data:
dataGridViewASINs:
i successfully scrape first page data but when i try to scrape 2nd data and try to put the data in the datagridview i get the error
index out of range. Must be non negative and **
I am also getting an error here when the loop comes back for the 2nd time and first data which i put into my DataGridView is title:
for (int i = 0; i < dataGridViewASINs.Rows.Count - 1; i++)
{
//Getting Title
string title = driver.FindElement(By.Id("productTitle")).GetAttribute("innerText");
dataGridViewScrapingData.Rows[i].Cells[cols].Value = title;
}
I am using this code for putting the data in the datagridview all the other columns code is similar to that i am using
Rows[index].Cells[Indexing]
for all the columns but for Combobox columns i didn't use this indexing i think so that also works only for first iteration
for (int i = 0; i < dataGridViewASINs.Rows.Count - 1; i++)
{
List<IWebElement> imageCounts = driver.FindElements(By.XPath("//ul[#class='a-unordered-list a-nostyle a-button-list a-vertical a-spacing-top-extra-large']//li[#class='a-spacing-small item imageThumbnail a-declarative']//span[#class='a-button-text']//img")).ToList();
element = driver.FindElement(By.Id("landingImage"));
comboState.Items.Add(element.GetAttribute("src"));
for (int j = 0; j < imageCounts.Count - 1; j++)
{
//Clicking that Element
string GenricXpath = "//ul[#class='a-unordered-list a-nostyle a-button-list a-vertical a-spacing-top-extra-large']//li[" + (j + 5).ToString() + "]//span[1]//span[1]//span[1]//input[1]";
element = driver.FindElement(By.XPath(GenricXpath)); element.Click();
//Extracting URL now
string AnotherXpath = "//li[#class='image item itemNo" + (j + 1).ToString() + " maintain-height selected']//img";
element = driver.FindElement(By.XPath(AnotherXpath)); comboState.Items.Add(element.GetAttribute("src"));
}
dataGridViewScrapingData.Columns.Add(comboState);
}
Other than that i also wanna know after putting data into datagridviewScrapingData. I don't know how i can get back the entire data which is in the combobox column in the DataGridViewScraping Data. I want to get the data into the List of string from the datagridviewScrapingData where i have saved my entire data. I have seen many questions relevant to that as well here on stackoverflow but none of them make any sense to me.
Looks like your approach of working with dataGridView is a bit incorrect. You try to work with the data grid rows directly, but the idea is to have a separate collection like List<Product> and display it through a binding source.
1. First create a class representing your product like:
public class Product
{
public string Title { get; set; }
public string Asin { get; set; }
}
2. Create a list of products and scrape them to that list.
3. Click on the dataGridView in form designer and note the arrow button at the top right corner. Click on it and generate a new datasource by selecting your Product class. DataGridBindingSource will appear at the bottom of the form designer. Let's assume it's name is dataGridViewBindingSource.
4. Assign your products collection to the binding source:
dataGridViewBindingSource.DataSource = products;
Now you can modify products collection and display updated products in the grid by calling dataGridView.Refresh() method. At this point you should get rid of "Index out of range" exception and you have a reference to your products collection, so you don't have to "extract" them explicitly from datagrid rows.
5. Instead of getting values from ComboBox you can store options in a product first and then add them to a combobox.
So, I have a DataGrid, that I want to manipulate programmatically a lot.
string[] values = new string[something.Count];
for (int i = 0; i < somethingElse.Count; i++)
{
if (condition)
values[i] = Data[i].ToString();
else
values[i] = "";
}
var style = new System.Windows.Style(typeof(DataGridRowHeader));
style.Setters.Add(new Setter(DataGridRowHeader.ContentProperty, Data[0].ToString()));
MyGrid.Items.Add(new DataGridRow()
{
HeaderStyle = style,
Item = values
});
This I do in a loop and I am able to fill in my grid with all the data I need.
Later, I am able to access cells, edit them, take their values, whatever I want and need.
However, when user wants to use the grid as you would in MS Excel, the cells are not editable.
So I went the other way and created a :
ObservableCollection<ObservableCollection<string>> gridData = new ObservableCollection<ObservableCollection<string>>();
//*** ... *** the gridData is filled in the same way, you can imagine
MyGrid.ItemsSource = gridData;
This does fill in the data perfectly the same way, more than that, the data are now editable.
But my custom row headers disappeared.
I need them, also, I do not think I want to use binding for row header values.
Can the first approach be somehow modified to still be editable, but rows with data being filled the very same way?
I eventually solved this combining both the abovementioned approaches.
First, I generate ObservableCollection<ObservableCollection<string>> dataCollection, fill it with data.
Next I generate an ObservableCollection<DataGridRow> rowCollection collection.
In my declarative part of the loop from the first approach, that you can see in the question, I do this
rowCollection.Add(new DataGridRow()
{
HeaderStyle = style,
Item = dataCollection[i] //for the corresponding iteration element
});
This all ends up when setting
MyGrid.ItemsSource = rowCollection;
Till now (very little time of testing), this seems to be what I was looking for, hope it might help someone else aswell.
I have a datagrid dgCompanies declare like this:
// bind the data to the datagrid
dgCompanies.PageSize = pageSize;
dgCompanies.DataSource = rdr;
Then I need to check the records inside this datagrid:
int j = 0;
foreach (DataGridItem item in dgCompanies.Items)
{
HtmlGenericControl name = (HtmlGenericControl)item.Cells[j].FindControl("SpanTitle");
string drstring = name.InnerHtml.Trim();
if (checkingfunction(drstring))
{
//do removing record from datagrid.
I tried this: item.Cells.Remove(item.Cells[j]); but the result still there, don't see anything removed!
}
j = j + 1;
}
dgCompanies.DataBind();
How could I remove that record from datagrid dgCompanies when if condition is satisfy ?
I agree with #Andrei, it would be best to just not return that data. Otherwise you're returning and churning through data that is unnecessary. However, if in the context of you can't filter the data up front, I suppose you could add a css class "donotshow" to your rows (see How do I specify CSS classes for specific rows in a GridView?).
Then using jquery use
$('.donotshow').hide();
Again, in this regard, you are still returning all that HTML to the browser, so that will make your page size larger than necessary. Additionally, using this method could screw up pagination if you using it (example, if it says "rows 1-10", but 5 rows are hidden, then that will look goofy).
Hope this helps
I have a datatable bound to a datagridview. However, the ordering of columns is messed up. I already made a column headers for each field put dataproperty name. I arranged it in the designer view. However, if i run the program column headers doesn't follow my arrangement. =_=. Does anybody know how to solve this....
EDIT::
I've Tried this approach. Is it Okay?
void SortDataGridViewColumns(DataGridView dgv)
{
var list = from DataGridViewColumn c in dgv.Columns
orderby c.Index
select c;
int i = 0;
foreach (DataGridViewColumn c in list)
{
c.DisplayIndex = i++;
}
}
***I've got this here but I use Index instead of Headertext. CASE CLOSED! LOL
I think you wil need to change the column order in runtime.
From MSDN:
When you use a DataGridView to display data from a data source, the columns in the data source's schema sometimes do not appear in the order you would like to display them. You can change the displayed order of the columns by using the DisplayIndex property of the DataGridViewColumn class.
You can change the order of the columns like this:
private void AdjustColumnOrder()
{
customersDataGridView.Columns["CustomerID"].Visible = false;
customersDataGridView.Columns["ContactName"].DisplayIndex = 0;
customersDataGridView.Columns["ContactTitle"].DisplayIndex = 1;
customersDataGridView.Columns["City"].DisplayIndex = 2;
customersDataGridView.Columns["Country"].DisplayIndex = 3;
customersDataGridView.Columns["CompanyName"].DisplayIndex = 4;
}
http://msdn.microsoft.com/en-us/library/wkfe535h.aspx#Y0
If you're going t use it frequently, I recomend you to make use of extension methods to add sintactic sugar and make it easy to read and maintain.
I'm dynamically adding rows to a datagridview this way:
Question question = new Question();
List<Question> questions = question.GetQuestionsByQuestionnaire(questionnaireId);
if (questions != null)
{
dgvQuestions.Columns.Add("Question", "Vraag");
dgvQuestions.Columns.Add("QuestionType", "Vraag type");
dgvQuestions.Columns.Add("Category", "Categorie");
for (int i = 0; i < questions.Count; i++ )
{
int row = dgvQuestions.Rows.Add();
dgvQuestions.Rows[row].Cells["Question"].Value = questions[i].Question;
dgvQuestions.Rows[row].Cells["QuestionType"].Value = questions[i].QuestionType;
dgvQuestions.Rows[row].Cells["Category"].Value = questions[i].Category;
dgvQuestions.Rows[row].Tag = questions[i];
}
}
I don't get any errors, but the cell value stays null and I'm 100% sure that Question, QuestionType and Category contains data. What am i missing here?
I'm not sure about why this is the case, but I'd go for a mix of dynamic data but typed dataset.
What you'd do is:
Create a typed DataSet, add a "Questions" table with the columns you need
Put an instance of your DataSet from the Toolbox on your form (must recompile before that), name it for example myDataSource.
Put a BindingSource on your form, assign the myDataSource to the DataSource property and select your table for the DataMember property.
Assign the binding source to the DataSource property of your DataGridView
Add data to the data source by using for example myDataSource.Questions.NewQuestionsRow() and myDataSource.Questions.AddQuestionsRow(...).
I've just encountered something similar. You might want to make sure EnableViewState is set to True for your GridView.
Make sure VitualMode is set to False for your GridView.