C# 从 datagridview 中删除空白单元格
C# Removing blank cells from datagridview
有没有办法从数据网格视图中删除 blank/null 单元格?
private void button1_Click(object sender, EventArgs e)
{
DataTable dvpdt = new DataTable();
HtmlAgilityPack.HtmlDocument doc;
doc = new HtmlWeb().Load("https://rotogrinders.com/grids/nba-defense-vs-position-cheat-sheet-1493632?site=fanduele");
HtmlNode node = doc.DocumentNode.SelectSingleNode("//section[@class='bdy content article full cflex reset long table-page']/following-sibling::script[1]");
//Atlanta DVP:
int atlantastart = node.InnerText.IndexOf("Atlanta Hawks");
int atlantalength = node.InnerText.IndexOf("Boston Celtics") - atlantastart;
string atlantaoutput = node.InnerText.Substring(atlantastart, atlantalength).Replace("TEAM", "").Replace("\"", "").Replace("{:", "").Replace("FPPG:", "").Trim();
string[] atlantasplit = atlantaoutput.Split(',');
DataColumn dc = new DataColumn("Atlanta Hawks");
DataColumn bdc = new DataColumn("Boston Celtics");
DataColumn brdc = new DataColumn("Brooklyn Nets");
dvpdt.Columns.Add(dc);
DataRow dr = dvpdt.NewRow();
foreach (string atlantaitem in atlantasplit)
{
dr = dvpdt.NewRow();
dr["Atlanta Hawks"] = atlantaitem;
dvpdt.Rows.Add(dr);
}
//Boston DVP:
int bostonstart = node.InnerText.IndexOf("Boston Celtics");
int bostonlength = node.InnerText.IndexOf("Brooklyn Nets") - bostonstart;
string bostonoutput = node.InnerText.Substring(bostonstart, bostonlength).Replace("TEAM", "").Replace("\"", "").Replace("{:", "").Replace("FPPG:", "").Trim();
string[] bostonsplit = bostonoutput.Split(',');
dvpdt.Columns.Add(bdc);
foreach (string bostonitem in bostonsplit)
{
dr = dvpdt.NewRow();
dr["Boston Celtics"] = bostonitem;
dvpdt.Rows.Add(dr);
}
//Brooklyn DVP:
int brooklynstart = node.InnerText.IndexOf("Brooklyn Nets");
int brooklynlength = node.InnerText.IndexOf("Charlotte Hornets") - brooklynstart;
string brooklynoutput = node.InnerText.Substring(brooklynstart, brooklynlength).Replace("TEAM", "").Replace("\"", "").Replace("{:", "").Replace("FPPG:", "").Trim();
string[] brooklynsplit = brooklynoutput.Split(',');
dvpdt.Columns.Add(brdc);
foreach (string brooklynitem in brooklynsplit)
{
dr = dvpdt.NewRow();
dr["Brooklyn Nets"] = brooklynitem;
dvpdt.Rows.Add(dr);
}
//end team load
//Bind Datasource
dataGridView2.DataSource = dvpdt;
foreach (DataGridViewRow row in dataGridView2.Rows)
{
string t = row.Cells[0].Value == null ? String.Empty : row.Cells[0].Value.ToString();
string a = row.Cells[1].Value == null ? String.Empty : row.Cells[1].Value.ToString();
string b = row.Cells[2].Value == null ? String.Empty : row.Cells[2].Value.ToString();
if (t.Contains("PG RK"))
{
dataGridView2.Rows.Remove(row);
}
if (t.Contains("SG RK"))
{
dataGridView2.Rows.Remove(row);
}
if (t.Contains("C RK"))
{
dataGridView2.Rows.Remove(row);
}
if (t.Contains("PF RK"))
{
dataGridView2.Rows.Remove(row);
}
if (t.Contains("SF RK"))
{
dataGridView2.Rows.Remove(row);
}
if (a.Contains("PG RK"))
{
dataGridView2.Rows.Remove(row);
}
if (a.Contains("SG RK"))
{
dataGridView2.Rows.Remove(row);
}
if (a.Contains("C RK"))
{
dataGridView2.Rows.Remove(row);
}
if (a.Contains("PF RK"))
{
dataGridView2.Rows.Remove(row);
}
if (a.Contains("SF RK"))
{
dataGridView2.Rows.Remove(row);
}
if (b.Contains("PG RK"))
{
dataGridView2.Rows.Remove(row);
}
if (b.Contains("SG RK"))
{
dataGridView2.Rows.Remove(row);
}
if (b.Contains("C RK"))
{
dataGridView2.Rows.Remove(row);
}
if (b.Contains("PF RK"))
{
dataGridView2.Rows.Remove(row);
}
if (b.Contains("SF RK"))
{
dataGridView2.Rows.Remove(row);
}
}
}
这是一个屏幕截图,展示了亚特兰大鹰队专栏订购时当前的样子。我试图让所有列匹配,以便我可以并排比较数据。
我尝试搜索类似的问题,但遇到了一些问题。我认为我发现的最接近的事情是将数据导入列表。
更新:我尝试了以下尝试将两列分开,但这也不起作用:
private void button1_Click(object sender, EventArgs e)
{
DataTable dvpdt = new DataTable();
HtmlAgilityPack.HtmlDocument doc;
doc = new HtmlWeb().Load("https://rotogrinders.com/grids/nba-defense-vs-position-cheat-sheet-1493632?site=fanduele");
HtmlNode node = doc.DocumentNode.SelectSingleNode("//section[@class='bdy content article full cflex reset long table-page']/following-sibling::script[1]");
DataColumn dc = new DataColumn("Atlanta Hawks");
DataColumn bdc = new DataColumn("Boston Celtics");
DataColumn brdc = new DataColumn("Brooklyn Nets");
DataRow dr = dvpdt.NewRow();
//Add Columns
dvpdt.Columns.Add(dc);
dvpdt.Columns.Add(bdc);
//Atlanta DVP:
int atlantastart = node.InnerText.IndexOf("Atlanta Hawks");
int atlantapglength = node.InnerText.IndexOf("PG RK") - atlantastart;
int atlantasglength = node.InnerText.IndexOf("SG RK") - atlantastart;
int atlantasflength = node.InnerText.IndexOf("SF RK") - atlantastart;
int atlantapflength = node.InnerText.IndexOf("PF RK") - atlantastart;
int atlantaclength = node.InnerText.IndexOf("C RK") - atlantastart;
string atlantapgoutput = node.InnerText.Substring(atlantastart, atlantapglength).Replace("TEAM", "").Replace("\"", "").Replace("{:", "").Replace("FPPG:", "").Replace("Atlanta Hawks", "");
string[] atlantapgsplit = atlantapgoutput.Split(',');
string atlantasgoutput = node.InnerText.Substring(atlantastart, atlantasglength).Replace("TEAM", "").Replace("\"", "").Replace("{:", "").Replace("FPPG:", "").Replace("Atlanta Hawks", "");
string[] atlantasgsplit = atlantasgoutput.Split(',');
foreach (string atlantaitem in atlantasgsplit)
{
dr = dvpdt.NewRow();
dr["Atlanta Hawks"] = atlantaitem;
dvpdt.Rows.Add(dr);
}
//Boston DVP:
int bostonstart = node.InnerText.IndexOf("Boston Celtics");
int bostonpglength = node.InnerText.IndexOf("PG RK") - atlantastart;
string bostonpgoutput = node.InnerText.Substring(bostonstart, bostonpglength).Replace("TEAM", "").Replace("\"", "").Replace("{:", "").Replace("FPPG:", "").Replace("Boston Celtics", "");
string[] bostonpgsplit = bostonpgoutput.Split(',');
foreach (string bostonitem in bostonpgsplit)
{
dr = dvpdt.NewRow();
dr["Boston Celtics"] = bostonitem;
dvpdt.Rows.Add(dr);
}
您在可以写入数据库之前将此空白添加到您的数据库中,然后打开 DataGridView 您没有看到任何空白
我相信发布的代码正在“创建”您要删除的空单元格。如果您跟踪代码,您会看到您正在为每个团队添加行,并且只是将每个团队移动到一列上。我猜你在添加下一个团队时应该 return 到网格的顶部。鉴于此,您要删除的单元格是通过不将下一个团队移动到第一行而“创建”的。该代码只是在三 (3) 个 foreach
循环中添加了一个新行。
从“大图”来看,您似乎正在从某个网站获得一些 NBA data/stats。 data/stats 以特定方式格式化。目标是“解析”data/stats,以便可以以可读的方式向用户显示数据。我希望我有这个权利。
为了提供帮助,我建议您创建一个 TeamStat
Class。原因是当您必须获得统计数据或团队时,它会让事情变得容易得多。目前,代码只是将值 (TeamStats) 添加到 DataTable
。 Class 可以像下面这样简单。
public class TeamStat {
public string TeamName { get; set; }
public List<string> TeamStats { get; set; }
public TeamStat(string teamName) {
TeamName = teamName;
TeamStats = new List<string>();
}
public TeamStat() {
TeamName = "";
TeamStats = new List<string>();
}
}
接下来,当代码从网站获取数据时,一直调用网站获取数据显得多余。一次挑选一个团队似乎没有必要。我建议您获取所有数据,因为您可以利用其格式。 “利用”,意味着我们要将统计数据分解(拆分)为团队!
仔细检查网站上的 returned 字符串后,“}”字符似乎出现在每支球队统计数据的末尾。这将允许代码在每个团队中“拆分”。关键是,当前代码只是为每个团队所需的数据获取一个子集。
我猜测使用 List<TeamStat>
可能会派上用场。通过这种方法,我正在考虑获取所有数据,并为所有团队用 TeamStat
填充 List
。使用这种方法,您可以按照自己喜欢的方式显示团队,而无需调用每个团队的网站。毫无疑问,这将更易于管理,并且从该列表中创建您选择的 DataTable
将是基本的。
GetAllStatsDataString
方法 return 是所有团队 data/stats 的半格式化字符串。 “开始”和“结束”索引来自对 returned 字符串的仔细检查。格式保持最少,并进行了编辑以促进将字符串“拆分”为“团队”的能力,这样每个团队的统计数据都以“}”(右括号)字符结尾。
private string GetAllStatsDataString() {
HtmlAgilityPack.HtmlDocument doc = new HtmlWeb().Load("https://rotogrinders.com/grids/nba-defense-vs-position-cheat-sheet-1493632?site=fanduele");
HtmlNode node = doc.DocumentNode.SelectSingleNode("//section[@class='bdy content article full cflex reset long table-page']/following-sibling::script[1]");
int TeamStart = node.InnerText.IndexOf("TEAM") + 4;
int TeamsEnd = node.InnerText.IndexOf("];") - TeamStart;
return node.InnerText.Substring(TeamStart, TeamsEnd).Replace("TEAM", "").Replace("\"", "").Replace("{","").Trim();
}
接下来是 GetAllTeamStats(string data)
,它从上面获取字符串 returned 并将其拆分为“}”字符,以获得包含每个团队统计数据的字符串数组。每个字符串数组条目将是一个团队名称及其 data/stats。创建一个 List<TeamStat>
stats
来保存每个团队的统计数据。在将团队添加到列表之前,我们需要将字符串转换为 TeamStat
object。这是通过 GetTeamStat
方法完成的。
private List<TeamStat> GetAllTeamStats(string data) {
List<TeamStat> stats = new List<TeamStat>();
string[] teamSplit = data.Split('}');
TeamStat curTeamStat;
foreach (string curTeam in teamSplit) {
if (curTeam != "") {
curTeamStat = GetTeamStat(curTeam);
stats.Add(curTeamStat);
}
}
return stats;
}
GetTeamStat
方法获取一个字符串,然后将该字符串解析为新的 TeamStat
object,return 就是 TeamStat
object,这又将被添加到前面方法中的 List<TeamStat>
TeamStat
。
private TeamStat GetTeamStat(string teamString) {
string[] statSplit = teamString.Substring(1).Split(',');
string tName = statSplit[0].Replace(":", "").Trim();
TeamStat teamStat = new TeamStat(tName);
for (int i = 1; i < statSplit.Length; i++) {
if (statSplit[i] != null && statSplit[i] != "") {
teamStat.TeamStats.Add(statSplit[i]);
}
}
return teamStat;
}
在这个阶段,我们现在有一个 TeamStat
object 的列表,每个团队一个。您可以将其用作数据源,但是如前所述,使用团队统计数据列表创建 DataTable
并不困难。这里唯一的问题是决定在 DataTable
中显示哪些球队。在下面的代码中,我简单地使用了所有球队,但是,只显示用户想要的球队并不困难。
考虑到这一点,不一定知道要显示多少列;因此,代码只是循环遍历列表中的所有团队,每个团队一列。下一个问题是假设每个团队之间的统计数据数量可能不同,table 需要多少行。为确保显示所有统计数据,将进行检查以获取所有团队的最大统计数据列表。这将确定所需的行数。最后,用 List<TeamStat>
TeamStats
中的数据填充这些行。下面是 return DataTable
的代码
private DataTable GetGridDT() {
DataTable dt = new DataTable();
SetDataTableColumnsAndRows(dt);
FillRows(dt);
return dt;
}
private void SetDataTableColumnsAndRows(DataTable dt) {
int totalRows = 0;
foreach(TeamStat curTeam in TeamStats) {
dt.Columns.Add(curTeam.TeamName, typeof(string));
totalRows = Math.Max(totalRows, curTeam.TeamStats.Count);
}
// set rows here to max length to avoid having to check for different length stats
for (int i = 0; i < totalRows; i++) {
dt.Rows.Add();
}
}
注意:这里的“拆分”是将统计名称和统计数据分开。例如,统计数据的形式为“PG RK:26”……在将此字符串拆分为“:”后,我们可以获得名称或值。
private void FillRows(DataTable dt) {
int currentColumn = 0;
int currentRow;
string[] splitArray;
foreach (TeamStat curTeam in TeamStats) {
currentRow = 0;
foreach (string curStat in curTeam.TeamStats) {
splitArray = curStat.Split(':');
dt.Rows[currentRow][currentColumn] = splitArray[1].Trim();
currentRow++;
}
currentColumn++;
}
}
最后,最后一个问题是为每个统计数据的网格添加行 headers。每个统计单元格当前都有统计信息“名称”,这就是用于行 headers 的内容。注意:在设置网格数据源后调用此方法。
private void SetGridRowHeaders() {
int rowIndex = 0;
string[] splitArray;
foreach (string curHeader in TeamStats[0].TeamStats) {
splitArray = curHeader.Split(':');
dataGridView1.Rows[rowIndex].HeaderCell.Value = splitArray[0].Trim();
rowIndex++;
}
}
最后是表单加载方法,将它们放在一起......
DataTable TeamDataTable;
string AllStatsString;
List<TeamStat> TeamStats;
public Form_NBA_Stats() {
InitializeComponent();
}
private void Form_NBA_Stats_Load(object sender, EventArgs e) {
AllStatsString = GetAllStatsDataString();
TeamStats = GetAllTeamStats(AllStatsString);
TeamDataTable = GetGridDT();
dataGridView1.DataSource = TeamDataTable;
SetGridRowHeaders();
}
希望这对您有所帮助。
您可以尝试这样的操作,我没有时间测试它,但它应该可以工作,如果经过一些更改后它不起作用,它可能会起作用,这可能会让您了解如何去做。
for (int i = dataGridView1.Rows.Count; i > -1; --i)
{
DataGridViewRow row = dataGridView1.Rows[i];
if (!row.IsNewRow && row.Cells[0].Value == null)
{
dataGridView1.Rows.RemoveAt(i);
}
DataGridViewColumn clmn = dataGridView1.Columns[i];
if (row.Cells[0].Value == null)
{
dataGridView1.Columns.RemoveAt(i);
}
}
如果您想删除任何空行或任何包含空单元格的行,您可以使用此代码:
for (int i = 0;i<dataGridView1.Rows.count-1;i++)
{
if (dataGridView1.Rows[i].Cells[0].Value.ToString() =="" | dataGridView1.Rows[i].Cells[1].Value.ToString()==""| dataGridView1.Rows[i].Cells[2].Value.ToString()=="")
{
dataGridView1.Rows.RemoveAt(i);
i--;
}}
有没有办法从数据网格视图中删除 blank/null 单元格?
private void button1_Click(object sender, EventArgs e)
{
DataTable dvpdt = new DataTable();
HtmlAgilityPack.HtmlDocument doc;
doc = new HtmlWeb().Load("https://rotogrinders.com/grids/nba-defense-vs-position-cheat-sheet-1493632?site=fanduele");
HtmlNode node = doc.DocumentNode.SelectSingleNode("//section[@class='bdy content article full cflex reset long table-page']/following-sibling::script[1]");
//Atlanta DVP:
int atlantastart = node.InnerText.IndexOf("Atlanta Hawks");
int atlantalength = node.InnerText.IndexOf("Boston Celtics") - atlantastart;
string atlantaoutput = node.InnerText.Substring(atlantastart, atlantalength).Replace("TEAM", "").Replace("\"", "").Replace("{:", "").Replace("FPPG:", "").Trim();
string[] atlantasplit = atlantaoutput.Split(',');
DataColumn dc = new DataColumn("Atlanta Hawks");
DataColumn bdc = new DataColumn("Boston Celtics");
DataColumn brdc = new DataColumn("Brooklyn Nets");
dvpdt.Columns.Add(dc);
DataRow dr = dvpdt.NewRow();
foreach (string atlantaitem in atlantasplit)
{
dr = dvpdt.NewRow();
dr["Atlanta Hawks"] = atlantaitem;
dvpdt.Rows.Add(dr);
}
//Boston DVP:
int bostonstart = node.InnerText.IndexOf("Boston Celtics");
int bostonlength = node.InnerText.IndexOf("Brooklyn Nets") - bostonstart;
string bostonoutput = node.InnerText.Substring(bostonstart, bostonlength).Replace("TEAM", "").Replace("\"", "").Replace("{:", "").Replace("FPPG:", "").Trim();
string[] bostonsplit = bostonoutput.Split(',');
dvpdt.Columns.Add(bdc);
foreach (string bostonitem in bostonsplit)
{
dr = dvpdt.NewRow();
dr["Boston Celtics"] = bostonitem;
dvpdt.Rows.Add(dr);
}
//Brooklyn DVP:
int brooklynstart = node.InnerText.IndexOf("Brooklyn Nets");
int brooklynlength = node.InnerText.IndexOf("Charlotte Hornets") - brooklynstart;
string brooklynoutput = node.InnerText.Substring(brooklynstart, brooklynlength).Replace("TEAM", "").Replace("\"", "").Replace("{:", "").Replace("FPPG:", "").Trim();
string[] brooklynsplit = brooklynoutput.Split(',');
dvpdt.Columns.Add(brdc);
foreach (string brooklynitem in brooklynsplit)
{
dr = dvpdt.NewRow();
dr["Brooklyn Nets"] = brooklynitem;
dvpdt.Rows.Add(dr);
}
//end team load
//Bind Datasource
dataGridView2.DataSource = dvpdt;
foreach (DataGridViewRow row in dataGridView2.Rows)
{
string t = row.Cells[0].Value == null ? String.Empty : row.Cells[0].Value.ToString();
string a = row.Cells[1].Value == null ? String.Empty : row.Cells[1].Value.ToString();
string b = row.Cells[2].Value == null ? String.Empty : row.Cells[2].Value.ToString();
if (t.Contains("PG RK"))
{
dataGridView2.Rows.Remove(row);
}
if (t.Contains("SG RK"))
{
dataGridView2.Rows.Remove(row);
}
if (t.Contains("C RK"))
{
dataGridView2.Rows.Remove(row);
}
if (t.Contains("PF RK"))
{
dataGridView2.Rows.Remove(row);
}
if (t.Contains("SF RK"))
{
dataGridView2.Rows.Remove(row);
}
if (a.Contains("PG RK"))
{
dataGridView2.Rows.Remove(row);
}
if (a.Contains("SG RK"))
{
dataGridView2.Rows.Remove(row);
}
if (a.Contains("C RK"))
{
dataGridView2.Rows.Remove(row);
}
if (a.Contains("PF RK"))
{
dataGridView2.Rows.Remove(row);
}
if (a.Contains("SF RK"))
{
dataGridView2.Rows.Remove(row);
}
if (b.Contains("PG RK"))
{
dataGridView2.Rows.Remove(row);
}
if (b.Contains("SG RK"))
{
dataGridView2.Rows.Remove(row);
}
if (b.Contains("C RK"))
{
dataGridView2.Rows.Remove(row);
}
if (b.Contains("PF RK"))
{
dataGridView2.Rows.Remove(row);
}
if (b.Contains("SF RK"))
{
dataGridView2.Rows.Remove(row);
}
}
}
这是一个屏幕截图,展示了亚特兰大鹰队专栏订购时当前的样子。我试图让所有列匹配,以便我可以并排比较数据。
我尝试搜索类似的问题,但遇到了一些问题。我认为我发现的最接近的事情是将数据导入列表。
更新:我尝试了以下尝试将两列分开,但这也不起作用:
private void button1_Click(object sender, EventArgs e)
{
DataTable dvpdt = new DataTable();
HtmlAgilityPack.HtmlDocument doc;
doc = new HtmlWeb().Load("https://rotogrinders.com/grids/nba-defense-vs-position-cheat-sheet-1493632?site=fanduele");
HtmlNode node = doc.DocumentNode.SelectSingleNode("//section[@class='bdy content article full cflex reset long table-page']/following-sibling::script[1]");
DataColumn dc = new DataColumn("Atlanta Hawks");
DataColumn bdc = new DataColumn("Boston Celtics");
DataColumn brdc = new DataColumn("Brooklyn Nets");
DataRow dr = dvpdt.NewRow();
//Add Columns
dvpdt.Columns.Add(dc);
dvpdt.Columns.Add(bdc);
//Atlanta DVP:
int atlantastart = node.InnerText.IndexOf("Atlanta Hawks");
int atlantapglength = node.InnerText.IndexOf("PG RK") - atlantastart;
int atlantasglength = node.InnerText.IndexOf("SG RK") - atlantastart;
int atlantasflength = node.InnerText.IndexOf("SF RK") - atlantastart;
int atlantapflength = node.InnerText.IndexOf("PF RK") - atlantastart;
int atlantaclength = node.InnerText.IndexOf("C RK") - atlantastart;
string atlantapgoutput = node.InnerText.Substring(atlantastart, atlantapglength).Replace("TEAM", "").Replace("\"", "").Replace("{:", "").Replace("FPPG:", "").Replace("Atlanta Hawks", "");
string[] atlantapgsplit = atlantapgoutput.Split(',');
string atlantasgoutput = node.InnerText.Substring(atlantastart, atlantasglength).Replace("TEAM", "").Replace("\"", "").Replace("{:", "").Replace("FPPG:", "").Replace("Atlanta Hawks", "");
string[] atlantasgsplit = atlantasgoutput.Split(',');
foreach (string atlantaitem in atlantasgsplit)
{
dr = dvpdt.NewRow();
dr["Atlanta Hawks"] = atlantaitem;
dvpdt.Rows.Add(dr);
}
//Boston DVP:
int bostonstart = node.InnerText.IndexOf("Boston Celtics");
int bostonpglength = node.InnerText.IndexOf("PG RK") - atlantastart;
string bostonpgoutput = node.InnerText.Substring(bostonstart, bostonpglength).Replace("TEAM", "").Replace("\"", "").Replace("{:", "").Replace("FPPG:", "").Replace("Boston Celtics", "");
string[] bostonpgsplit = bostonpgoutput.Split(',');
foreach (string bostonitem in bostonpgsplit)
{
dr = dvpdt.NewRow();
dr["Boston Celtics"] = bostonitem;
dvpdt.Rows.Add(dr);
}
您在可以写入数据库之前将此空白添加到您的数据库中,然后打开 DataGridView 您没有看到任何空白
我相信发布的代码正在“创建”您要删除的空单元格。如果您跟踪代码,您会看到您正在为每个团队添加行,并且只是将每个团队移动到一列上。我猜你在添加下一个团队时应该 return 到网格的顶部。鉴于此,您要删除的单元格是通过不将下一个团队移动到第一行而“创建”的。该代码只是在三 (3) 个 foreach
循环中添加了一个新行。
从“大图”来看,您似乎正在从某个网站获得一些 NBA data/stats。 data/stats 以特定方式格式化。目标是“解析”data/stats,以便可以以可读的方式向用户显示数据。我希望我有这个权利。
为了提供帮助,我建议您创建一个 TeamStat
Class。原因是当您必须获得统计数据或团队时,它会让事情变得容易得多。目前,代码只是将值 (TeamStats) 添加到 DataTable
。 Class 可以像下面这样简单。
public class TeamStat {
public string TeamName { get; set; }
public List<string> TeamStats { get; set; }
public TeamStat(string teamName) {
TeamName = teamName;
TeamStats = new List<string>();
}
public TeamStat() {
TeamName = "";
TeamStats = new List<string>();
}
}
接下来,当代码从网站获取数据时,一直调用网站获取数据显得多余。一次挑选一个团队似乎没有必要。我建议您获取所有数据,因为您可以利用其格式。 “利用”,意味着我们要将统计数据分解(拆分)为团队!
仔细检查网站上的 returned 字符串后,“}”字符似乎出现在每支球队统计数据的末尾。这将允许代码在每个团队中“拆分”。关键是,当前代码只是为每个团队所需的数据获取一个子集。
我猜测使用 List<TeamStat>
可能会派上用场。通过这种方法,我正在考虑获取所有数据,并为所有团队用 TeamStat
填充 List
。使用这种方法,您可以按照自己喜欢的方式显示团队,而无需调用每个团队的网站。毫无疑问,这将更易于管理,并且从该列表中创建您选择的 DataTable
将是基本的。
GetAllStatsDataString
方法 return 是所有团队 data/stats 的半格式化字符串。 “开始”和“结束”索引来自对 returned 字符串的仔细检查。格式保持最少,并进行了编辑以促进将字符串“拆分”为“团队”的能力,这样每个团队的统计数据都以“}”(右括号)字符结尾。
private string GetAllStatsDataString() {
HtmlAgilityPack.HtmlDocument doc = new HtmlWeb().Load("https://rotogrinders.com/grids/nba-defense-vs-position-cheat-sheet-1493632?site=fanduele");
HtmlNode node = doc.DocumentNode.SelectSingleNode("//section[@class='bdy content article full cflex reset long table-page']/following-sibling::script[1]");
int TeamStart = node.InnerText.IndexOf("TEAM") + 4;
int TeamsEnd = node.InnerText.IndexOf("];") - TeamStart;
return node.InnerText.Substring(TeamStart, TeamsEnd).Replace("TEAM", "").Replace("\"", "").Replace("{","").Trim();
}
接下来是 GetAllTeamStats(string data)
,它从上面获取字符串 returned 并将其拆分为“}”字符,以获得包含每个团队统计数据的字符串数组。每个字符串数组条目将是一个团队名称及其 data/stats。创建一个 List<TeamStat>
stats
来保存每个团队的统计数据。在将团队添加到列表之前,我们需要将字符串转换为 TeamStat
object。这是通过 GetTeamStat
方法完成的。
private List<TeamStat> GetAllTeamStats(string data) {
List<TeamStat> stats = new List<TeamStat>();
string[] teamSplit = data.Split('}');
TeamStat curTeamStat;
foreach (string curTeam in teamSplit) {
if (curTeam != "") {
curTeamStat = GetTeamStat(curTeam);
stats.Add(curTeamStat);
}
}
return stats;
}
GetTeamStat
方法获取一个字符串,然后将该字符串解析为新的 TeamStat
object,return 就是 TeamStat
object,这又将被添加到前面方法中的 List<TeamStat>
TeamStat
。
private TeamStat GetTeamStat(string teamString) {
string[] statSplit = teamString.Substring(1).Split(',');
string tName = statSplit[0].Replace(":", "").Trim();
TeamStat teamStat = new TeamStat(tName);
for (int i = 1; i < statSplit.Length; i++) {
if (statSplit[i] != null && statSplit[i] != "") {
teamStat.TeamStats.Add(statSplit[i]);
}
}
return teamStat;
}
在这个阶段,我们现在有一个 TeamStat
object 的列表,每个团队一个。您可以将其用作数据源,但是如前所述,使用团队统计数据列表创建 DataTable
并不困难。这里唯一的问题是决定在 DataTable
中显示哪些球队。在下面的代码中,我简单地使用了所有球队,但是,只显示用户想要的球队并不困难。
考虑到这一点,不一定知道要显示多少列;因此,代码只是循环遍历列表中的所有团队,每个团队一列。下一个问题是假设每个团队之间的统计数据数量可能不同,table 需要多少行。为确保显示所有统计数据,将进行检查以获取所有团队的最大统计数据列表。这将确定所需的行数。最后,用 List<TeamStat>
TeamStats
中的数据填充这些行。下面是 return DataTable
private DataTable GetGridDT() {
DataTable dt = new DataTable();
SetDataTableColumnsAndRows(dt);
FillRows(dt);
return dt;
}
private void SetDataTableColumnsAndRows(DataTable dt) {
int totalRows = 0;
foreach(TeamStat curTeam in TeamStats) {
dt.Columns.Add(curTeam.TeamName, typeof(string));
totalRows = Math.Max(totalRows, curTeam.TeamStats.Count);
}
// set rows here to max length to avoid having to check for different length stats
for (int i = 0; i < totalRows; i++) {
dt.Rows.Add();
}
}
注意:这里的“拆分”是将统计名称和统计数据分开。例如,统计数据的形式为“PG RK:26”……在将此字符串拆分为“:”后,我们可以获得名称或值。
private void FillRows(DataTable dt) {
int currentColumn = 0;
int currentRow;
string[] splitArray;
foreach (TeamStat curTeam in TeamStats) {
currentRow = 0;
foreach (string curStat in curTeam.TeamStats) {
splitArray = curStat.Split(':');
dt.Rows[currentRow][currentColumn] = splitArray[1].Trim();
currentRow++;
}
currentColumn++;
}
}
最后,最后一个问题是为每个统计数据的网格添加行 headers。每个统计单元格当前都有统计信息“名称”,这就是用于行 headers 的内容。注意:在设置网格数据源后调用此方法。
private void SetGridRowHeaders() {
int rowIndex = 0;
string[] splitArray;
foreach (string curHeader in TeamStats[0].TeamStats) {
splitArray = curHeader.Split(':');
dataGridView1.Rows[rowIndex].HeaderCell.Value = splitArray[0].Trim();
rowIndex++;
}
}
最后是表单加载方法,将它们放在一起......
DataTable TeamDataTable;
string AllStatsString;
List<TeamStat> TeamStats;
public Form_NBA_Stats() {
InitializeComponent();
}
private void Form_NBA_Stats_Load(object sender, EventArgs e) {
AllStatsString = GetAllStatsDataString();
TeamStats = GetAllTeamStats(AllStatsString);
TeamDataTable = GetGridDT();
dataGridView1.DataSource = TeamDataTable;
SetGridRowHeaders();
}
希望这对您有所帮助。
您可以尝试这样的操作,我没有时间测试它,但它应该可以工作,如果经过一些更改后它不起作用,它可能会起作用,这可能会让您了解如何去做。
for (int i = dataGridView1.Rows.Count; i > -1; --i)
{
DataGridViewRow row = dataGridView1.Rows[i];
if (!row.IsNewRow && row.Cells[0].Value == null)
{
dataGridView1.Rows.RemoveAt(i);
}
DataGridViewColumn clmn = dataGridView1.Columns[i];
if (row.Cells[0].Value == null)
{
dataGridView1.Columns.RemoveAt(i);
}
}
如果您想删除任何空行或任何包含空单元格的行,您可以使用此代码:
for (int i = 0;i<dataGridView1.Rows.count-1;i++)
{
if (dataGridView1.Rows[i].Cells[0].Value.ToString() =="" | dataGridView1.Rows[i].Cells[1].Value.ToString()==""| dataGridView1.Rows[i].Cells[2].Value.ToString()=="")
{
dataGridView1.Rows.RemoveAt(i);
i--;
}}