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--;
                }}