C# Node Collection using HTMLAgilityPack to Data table - c#

I am trying to scrape data from this site. I am able to obtain the data but now I need add the selected data to a data table. The following is very near complete but it is only returning the last record. I know its something simple but just cant figure it out. Essentially, the commented out portion for the Console.Writeline portion in the for loop will be the desired results in the datagridview after all said and done.
private void button1_Click(object sender, EventArgs e)
{
var doc = new HtmlWeb().Load("https://www.sportingcharts.com/nba/defense-vs-position/");
HtmlAgilityPack.HtmlNodeCollection teams = doc.DocumentNode.SelectNodes("//div[#class='col col-md-3']//tr/td[2]");
HtmlAgilityPack.HtmlNodeCollection points = doc.DocumentNode.SelectNodes(".//div[#class='col col-md-3']//tr/td[3]");
HtmlAgilityPack.HtmlNodeCollection positions = doc.DocumentNode.SelectNodes(".//div[#class='col col-md-3']//span[1]");
DataTable dvp_dt = new DataTable();
dvp_dt.Columns.Add("Team", typeof(string));
dvp_dt.Columns.Add("Points", typeof(string));
dvp_dt.Columns.Add("Position", typeof(string));
string[] positions_aux = positions.Where(x => x.InnerText.Length >= 6).Select(y => y.InnerText).ToArray();
DataRow row = dvp_dt.NewRow();
for (int i = 0; i < teams.Count - 1; i++)
{
var aux = i / 30;
row["Team"] = (teams[i].InnerText);
row["Points"] = (points[i].InnerText);
row["Position"] = (positions_aux[aux]);
// Console.WriteLine(teams[i].InnerText + ' ' + points[i].InnerText + ' ' + positions_aux[aux]);
}
dvp_dt.Rows.Add(row);
dataGridView2.DataSource = dvp_dt;
}

Try following :
for (int i = 0; i < teams.Count - 1; i++)
{
DataRow row = dvp_dt.NewRow();
var aux = i / 30;
row["Team"] = (teams[i].InnerText);
row["Points"] = (points[i].InnerText);
row["Position"] = (positions_aux[aux]);
}
dataGridView2.DataSource = null;
dataGridView2.DataSource = dvp_dt;

Related

Row already belongs to another table error when trying to add rows?

I tried this solution below:
This Row already belongs to another table error when trying to add rows?
I have a Datatable that contains 597 Columns and 20 Rows and are trying to export the data to excel. However, Excel has a maximum column count 256 and so I need to divide the source data into 3 datatables to make the export work.
Below is the code I have written.
var dtmasterdata = data.Tables[name];
for (int j = 1; j < datatableNumberCount; j++)
{
DataTable dt2 = new DataTable();
dt2.TableName = "Master_" + j;
dt2 = dtmasterdata.Copy();
foreach (DataColumn col in dtmasterdata.Columns)
{
DataColumn dtcol = new DataColumn();
dtcol = col;
dt2.Columns.Add(dtcol.ColumnName, dtcol.DataType);
}
for (int k = 0; k < dtmasterdata.Rows.Count; k++)
{
DataRow dr = dt2.NewRow();
dr = dtmasterdata.Rows[k];
dt2.ImportRow(dtmasterdata.Rows[k]);
//dt2.Rows.Add(dr.ItemArray);
}
After that I need to delete few columns like below and I want to create 3 datatables
foreach (DataColumn col in dtmasterdata.Columns)
{
if (j == 1)
{
// condition 1
if (col.Ordinal >= 255)
{
dt2.Columns.RemoveAt(col.Ordinal);
}
}
if (j == 2)
{
// condition 2.
if (col.Ordinal < 255 || col.Ordinal >= 510)
{
dt2.Columns.RemoveAt(col.Ordinal);
}
}
if (j == 3)
{
// condition 3.
if (col.Ordinal <= 510 || col.Ordinal >= 765)
{
dt2.Columns.Add(col);
}
}
}
int worksheetNumber = 1;
string worksheetNameWithNumber = "Master Data";
if (worksheetNumber > 1)
worksheetNameWithNumber = String.Format("{0}_{1}", ws1, worksheetNumber.ToString());
Infragistics.Excel.Worksheet worksheet = wb.Worksheets.Add(worksheetNameWithNumber);
Infragistics.WebUI.UltraWebGrid.UltraWebGrid masterData1 = new Infragistics.WebUI.UltraWebGrid.UltraWebGrid("masterDataGrid");
masterData1.Browser = Infragistics.WebUI.UltraWebGrid.BrowserLevel.UpLevel;
masterData1.DataSource = dt2;
masterData1.DataMember = "Master_" + j;
masterData1.DisplayLayout.HeaderStyleDefault.Font.Bold = true;
masterData1.DisplayLayout.HeaderStyleDefault.Font.Name = "Arial";
masterData1.DisplayLayout.HeaderStyleDefault.Font.Size = FontUnit.Parse("10px");
masterData1.DisplayLayout.HeaderStyleDefault.BackColor = System.Drawing.Color.LightGray;
masterData1.DisplayLayout.RowStyleDefault.Font.Name = "Arial";
masterData1.DisplayLayout.RowStyleDefault.Font.Size = FontUnit.Parse("10px");
Infragistics.WebUI.UltraWebGrid.UltraGridBand masterBand1 = new Infragistics.WebUI.UltraWebGrid.UltraGridBand();
masterData1.Bands.Add(masterBand1);
dgResults.Controls.Add(masterData1);
masterData1.DataBind();
wb.ActiveWorksheet = worksheet;
this.ugWebGridExporter.Export(masterData1, worksheet);
worksheetNumber++;
Your error is because you are trying to add a column to a datatable that already belongs to your source datatable.
dt2.Columns.Add(col);
You can't just iterate through the columns of a datatable and add them to another.
I've a solution to this, which involves cloning the source data and removing what you don't need.
1st, make 3 clones of the datatables you need. Below is an example with me creating my own source table with 596 columns. Notice that clone only takes the data table structure, no data!
var source597ColsTable = new DataTable("Source");
for (var i = 0; i <= 596; i++)
{
source597ColsTable.Columns.Add(new DataColumn("Column" + i , typeof(string)));
}
DataRow newRow = source597ColsTable.NewRow();
source597ColsTable.Rows.Add(newRow);
var cols0To199Table = source597ColsTable.Clone();
var cols200To399Table = source597ColsTable.Clone();
var cols400To596Table = source597ColsTable.Clone();
Next copy all the rows from the source table into the clones. The below is a simple function to do so.
private DataTable CopyRowsFromSource(DataTable sourceTable, DataTable destinationTable)
{
foreach (DataRow row in sourceTable.Rows)
{
destinationTable.Rows.Add(row.ItemArray);
}
return destinationTable;
}
Then call this function for each of your tables.
cols0To199Table = CopyRowsFromSource(source597ColsTable, cols0To199Table);
cols200To399Table = CopyRowsFromSource(source597ColsTable, cols200To399Table);
cols400To596Table = CopyRowsFromSource(source597ColsTable, cols400To596Table);
Finally, remove all the columns from the datatables to give you your split.
private DataTable RemoveColumns(DataTable table, int startCol, int endCol)
{
var colsToRemove = new List<DataColumn>();
for (var colCount = startCol; colCount <= endCol; colCount++)
{
colsToRemove.Add(table.Columns[colCount]);
}
foreach (DataColumn col in colsToRemove)
{
table.Columns.Remove(col);
}
return table;
}
Then call.. again for each cloned table.
cols0To199Table = RemoveColumns(cols0To199Table, 200, 596);
cols200To399Table = RemoveColumns(cols200To399Table, 0, 199);
cols200To399Table = RemoveColumns(cols200To399Table, 200, 396);
cols400To596Table = RemoveColumns(cols400To596Table, 0, 399);
After running this, you will have 3 datatables, columns 0-199, 200-399 and 400-596.
Hope that helps.
I am not sure to have really understood all of your code, but to copy a subset of columns to another datatable there is a very simple method in the DataView class named ToTable where you can list the columns you want in the new table. As added bonus, this method copies also the data in the 20 rows of your original table.
So the only difficult is to list these columns to the method.
You can proceed in this way using linq over the DataColumn collection
string[] firstCols = dtmasterdata.Columns
.Cast<DataColumn>()
.Take(255)
.Select(x => x.ColumnName).ToArray();
string[] secondCols = dtmasterdata.Columns
.Cast<DataColumn>()
.Skip(255)
.Take(255)
.Select(x => x.ColumnName).ToArray();
string[] thirdCols = dtmasterdata.Columns
.Cast<DataColumn>()
.Skip(510)
.Select(x => x.ColumnName).ToArray();
DataTable t1 = dtmasterdata.DefaultView.ToTable("Master_1", false, firstCols);
DataTable t2 = dtmasterdata.DefaultView.ToTable("Master_2", false, secondCols);
DataTable t3 = dtmasterdata.DefaultView.ToTable("Master_3", false, thirdCols);

How to move GridView multiple rows up and down?

I have a devexpress gridview bound to a datatable, right now I move one row up and down, by following some topic post on this blog.
What I need is to move multiple rows up and down.
for example on the button click event I have this
private void btnMoveMotor_Up_Click(object sender, EventArgs e)
{
GridView view = gridView_Motores;
view.GridControl.Focus();
int index = view.FocusedRowHandle;
if (index <= 0) return;
DataRow row1 = view.GetDataRow(index);
DataRow row2 = view.GetDataRow(index - 1);
object idcentg = row1[Codigo];
object idbatg = row1[batg];
object idunig = row1[unig];
object pot_cal = row1[potCalculada];
object pot_trab = row1[potTrabajo];
object idcentg1 = row2[Codigo];
object idbatg1 = row2[batg];
object idunig1 = row2[unig];
object pot_cal1 = row2[potCalculada];
object pot_trab1 = row2[potTrabajo];
row1[Codigo] = idcentg1;
row1[batg] = idbatg1;
row1[unig] = idunig1;
row1[potCalculada] = pot_cal1;
row1[potTrabajo] = pot_trab1;
row2[Codigo] = idcentg;
row2[batg] = idbatg;
row2[unig] = idunig;
row2[potCalculada] = pot_cal;
row2[potTrabajo] = pot_trab;
view.FocusedRowHandle = index - 1;
btnAplicar.Enabled = true;
btnAplicarOrdenMotores.Enabled = true;
}
Thanks!!!
I don't know how you actually move your row since you didn't post this solution, but maybe you just looking for following options to set
gridView1.OptionsSelection.MultiSelect = true;
gridView1.OptionsSelection.MultiSelectMode = DevExpress.XtraGrid.Views.Grid.GridMultiSelectMode.RowSelect;
and your code will work with multiple rows just like for one row.
if (view.SelectedRowsCount == 1)
{
// I do what I post in my question
}
if(view.SelectedRowsCount > 1)
{
int[] pos = new int[view.SelectedRowsCount];
pos = view.GetSelectedRows();//save into an array the selected rows handle
int lastHandle = pos.Last();
DataTable tableAux = new DataTable();
tableAux.Columns.Add("idcentg", typeof(string));
tableAux.Columns.Add("idbatg", typeof(int));
tableAux.Columns.Add("idunig", typeof(int));
tableAux.Columns.Add("potCalculada", typeof(decimal));
tableAux.Columns.Add("potTrabajo", typeof(decimal));
tableAux.Columns.Add("orden", typeof(int));
tableAux.Columns.Add("capinsg", typeof(decimal));
for (int i = 0; i < gridView_Motores.DataRowCount; i++)
{
tableAux.Rows.Add(gridView_Motores.GetRowCellValue(i,"idcentg"), gridView_Motores.GetRowCellValue(i, "idbatg"),
gridView_Motores.GetRowCellValue(i, "idunig"), gridView_Motores.GetRowCellValue(i, "potCalculada"),
gridView_Motores.GetRowCellValue(i, "potTrabajo"), gridView_Motores.GetRowCellValue(i, "orden"),
gridView_Motores.GetRowCellValue(i, "capinsg"));
}
int tag = 1;
int cont = 1;
for (int i = 0; i < pos.Length; i++)
{
if (tag == 1)
{
DataRow selectedRow = tableAux.Rows[pos[i]];
DataRow newRow = tableAux.NewRow();
newRow.ItemArray = selectedRow.ItemArray;
tableAux.Rows.Remove(selectedRow);
tableAux.Rows.InsertAt(newRow, lastHandle + 1);
}
else
{
DataRow selectedRow = tableAux.Rows[pos[i] - cont];
DataRow newRow = tableAux.NewRow();
newRow.ItemArray = selectedRow.ItemArray;
tableAux.Rows.Remove(selectedRow);
tableAux.Rows.InsertAt(newRow, lastHandle + 1);
cont++;
}
tag++;
}
int orden = 1;
foreach (DataRow row in tableAux.Rows)
{
row["orden"] = orden;
orden++;
}
grid_OrdenMotores.DataSource = null;
grid_OrdenMotores.DataSource = tableAux;
}

A data item was not found in the container. The container must either implement IDataItemContainer, or have a property named DataItem

I am trying to bind string array to grid view. While using the given below code showing the error "A data item was not found in the container. The container must either implement IDataItemContainer, or have a property named DataItem." Please help me to find a proper solution. Thank you.
Code:
protected void ddlCircle_SelectedIndexChanged(object sender, EventArgs e)
{
ShadingAnalysisDataSetTableAdapters.tbl_CadEngineersTeamTableAdapter cd;
cd = new ShadingAnalysisDataSetTableAdapters.tbl_CadEngineersTeamTableAdapter();
DataTable dt = new DataTable();
dt = cd.GetAvailableData(ddlCircle.SelectedValue); // Getting details of unassigned site
int x, y; //z;
DataTable dt3 = new DataTable();
dt3 = cd.GetTeam();
y = dt3.Rows.Count;
x = dt.Rows.Count; // counting the unassinged sites
DataTable dt2 = new DataTable();
dt2 = cd.GetAssignTeam(x); //Getting team based on count
string[] arr = new string[dt2.Rows.Count];
int i = 0;
foreach (DataRow r in dt2.Rows)
{
arr[i] = r["Team"].ToString(); // assigning available team to array
i++;
}
string[] strArr = new string[100]; // another array to copy arr values.
i = 0; int j = 0;
while (j <= x)
{
strArr[j]= arr[i] ; // copying the arr[] values into strArr[] based on count.
i++;
j++;
if (i == 3)
{
i = 0;
}
}
GridView2.DataSource = strArr;
GridView2.DataBind(); // error popup here
}
Define a GridView's column such that it binds to the Team column of your DataTable and assign the DataTable directly to the GridView as DataSource. Then DataBind to the DataTable.
Binding Array to DataGrid is just like putting bananas in egg tray. Please you have to bind a source having structure according to datagrid. As suggested by #Konstantin D - Infragistics
Now the gridview showing strArr[j] array values
protected void ddlCircle_SelectedIndexChanged(object sender, EventArgs e)
{
ShadingAnalysisDataSetTableAdapters.tbl_CadEngineersTeamTableAdapter cd;
cd = new ShadingAnalysisDataSetTableAdapters.tbl_CadEngineersTeamTableAdapter();
DataTable dt = new DataTable();
dt = cd.GetAvailableData(ddlCircle.SelectedValue); // Getting details of unassigned site
int x, y; //z;
DataTable dt3 = new DataTable();
dt3 = cd.GetTeam();
y = dt3.Rows.Count;
x = dt.Rows.Count; // counting the unassinged sites
DataTable dt2 = new DataTable();
dt2 = cd.GetAssignTeam(x); //Getting team based on count
string[] arr = new string[dt2.Rows.Count];
int i = 0;
foreach (DataRow r in dt2.Rows)
{
arr[i] = r["Team"].ToString(); // assigning available team to array
i++;
}
string[] strArr = new string[x+1]; // another array to copy arr values.
i = 0; int j = 0;
while (j <= x)
{
strArr[j]= arr[i] ; // copying the arr[] values into strArr[] based on count.
i++;
j++;
if (i == 3)
{
i = 0;
}
}
GridView2.DataSource = strArr;
GridView2.DataBind();
}

DropDownCheckBoxes doesn't bind with DataSet values

I'm using DropDownCheckBoxes CodePlex control. This works fine with the below code
var t = new string[20];
var currentYear = DateTime.Now.Year;
for (int i = 0; i < t.Length; i++)
t[i] = "Test " + i.ToString();
DropDownCheckBoxes1.DataSource = t;
DropDownCheckBoxes1.DataBind();
But when I use the same logic and get the value from DataSet, it doesn't work. DropDownCheckBoxes1 is not loaded with any values. Please let me know what is wrong here. I know we can reduce the code here and directly assign DropDownCheckBoxes1.DataSource = q.Distinct() but nothing is working for me
DataSet ds = GetTheData("Jan 2014");
DataTable dt = ds.Tables[0];
var q = from a in dt.AsEnumerable()
where a.Field<string>("SomeColumn1") == "Jan 2014"
select a.Field<string>("SomeColumn2");
var s = q.Distinct().ToList();
var years = new string[s.Count];
for (int i = 0; i < s.Count; i++)
years[i] = s[i];
DropDownCheckBoxes1.DataSource = years;
DropDownCheckBoxes1.DataBind();
Try this:
DataSet ds = GetTheData("Jan 2014");
DataTable dt = ds.Tables[0];
var q = dt.AsEnumerable().Where(a => a.Field<String>("SomeColumn1") == "Jan 2014")
.Select(a => a.Field<String>("SomeColumn2"));
DropDownCheckBoxes1.DataSource = q;
DropDownCheckBoxes1.DataBind();

Dynamic CheckBoxes in GridView Rows are not showing properly in ASP.NET

I have a gridview in which i am showing values to be checked or unchecked in gridview rows checkboxes..Now i want to these values dynamically in gridview rows but its not going to happen ..All of the checkboxes are coming checked whereas result should be different ..
here is my hardcoded code condition to show the result which is coming fine...
string[] rolesarr = Roles.GetAllRoles();
DataTable dTable = new DataTable();
dTable.Columns.Add("Select", typeof(bool));
dTable.Columns.Add("Username", typeof(string));
Array.ForEach(rolesarr, r => dTable.Columns.Add(r, typeof(bool)));
foreach (MembershipUser u in Membership.GetAllUsers())
{
DataRow dRow = dTable.NewRow();
dRow[0] = false;
dRow[1] = u.UserName;
string[] roles = Roles.GetRolesForUser(u.UserName);
dRow[2] = roles.Contains("Admin") ? true : false;
dRow[3] = roles.Contains("DPAO User") ? true : false;
dRow[4] = roles.Contains("GeneralUser") ? true : false;
dTable.Rows.Add(dRow);
}
GridView1.DataSource = dTable;
GridView1.DataBind();
Now i want to make this condition dynamic for which i have written code..
string[] rolesarr = Roles.GetAllRoles();
DataTable dTable = new DataTable();
dTable.Columns.Add("Select", typeof(bool));
dTable.Columns.Add("Username", typeof(string));
Array.ForEach(rolesarr, r => dTable.Columns.Add(r, typeof(bool)));
foreach (MembershipUser u in Membership.GetAllUsers())
{
DataRow dRow = dTable.NewRow();
dRow[0] = false;
dRow[1] = u.UserName;
string[] roles = Roles.GetRolesForUser(u.UserName);
for (int i = 0; i < roles.Length; i++)
{
string rol = roles[i];
for (int j = 2; j < dTable.Columns.Count; j++)
{
dRow[j] = roles.Contains(rol) ? true : false;
}
}
dTable.Rows.Add(dRow);
}
GridView1.DataSource = dTable;
GridView1.DataBind();
And Here is my RowDatabound event for checkboxes ..
protected void GridView1_RowDataBound1(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
CheckBox c0 = (CheckBox)e.Row.Cells[0].Controls[0];
CheckBox c2 = (CheckBox)e.Row.Cells[2].Controls[0];
CheckBox c3 = (CheckBox)e.Row.Cells[3].Controls[0];
CheckBox c4 = (CheckBox)e.Row.Cells[4].Controls[0];
c0.Enabled = c2.Enabled = c3.Enabled = c4.Enabled = true;
}
}
Please guys help me ..Thanks in advance...
the problem should be the double loops you provided.
According to your hardcoded code, you want to map between roles in the array rolesarr and roles of users, to show which roles is checked for each user.
To set values for data row at indext 2 - 4, you will have two loops, first loop to repeat rolesarr array and second loop to repeat roles array and compare them in the second loop
This is the code I mean:
string[] rolesarr = Roles.GetAllRoles();
DataTable dTable = new DataTable();
dTable.Columns.Add("Select", typeof(bool));
dTable.Columns.Add("Username", typeof(string));
Array.ForEach(rolesarr, r => dTable.Columns.Add(r, typeof(bool)));
foreach (MembershipUser u in Membership.GetAllUsers())
{
DataRow dRow = dTable.NewRow();
dRow[0] = false;
dRow[1] = u.UserName;
string[] roles = Roles.GetRolesForUser(u.UserName);
for (int i = 0; i < rolesarr.Length; i++)
{
for (int j = 0; j < roles.Length; j++)
{
if (rolesarr[i] == roles[j])
{
dRow[i + 2] = true;
break;
}
}
}
dTable.Rows.Add(dRow);
}
GridView1.DataSource = dTable;
GridView1.DataBind();
Please notice that I use data row index as i + 2 (dRow[i + 2]) in the second loop, because your role columns start at index=2, not 0, and the length must equal rolesarr.Length which you use them as role colums.

Categories