试图删除一个空列 - winform

Trying to remove an empty column - winform

我在 winform 中创建了一个小项目来显示 mhtml 文件中的数据网格视图。 一切正常。我想在我的项目中添加一些东西:当我看到一个空列时,我想将其删除(如果有的话)。 我几乎做到了,但我有一个错误。
这是代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MHtmlTablesHunter
{
    public partial class Form1 : Form
    {
        private readonly string ConvertedFileName = "page.html";

        private readonly List<string> ColumnsToSeparate = new List<string>() { "life limit", "interval" }; // Delete these columns 

        private readonly List<string> ExtraColumnsToAdd = new List<string>() { "Calendar", "Flight Hours", "Landing" }; // Add these columns
        public Form1()
        {
            InitializeComponent();
            this.Text = $"MhtmlTablesHunter v{Application.ProductVersion}";

        }

        //browse for specific file type , in this case its .mhtml
        private void btnBrowse_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog openFileDialog = new OpenFileDialog())
            {
                openFileDialog.Title = "Please choose the MHTML file";
                openFileDialog.Filter = "MHTML files (*.mhtml)|*.mhtml;";  //the file type specified here
                openFileDialog.RestoreDirectory = false;

                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    textBoxSourceFile.Text = openFileDialog.FileName;
                    checkAndExtractTable();
                }
            }

        }

        private void checkAndExtractTable()
        {
            string sourcePath =   textBoxSourceFile.Text;
            if (!string.IsNullOrEmpty(sourcePath)) //check if the input file path is not empty
            {
                if (File.Exists(sourcePath)) //check if the input file path is exists
                {
                    Task.Run(async () => await ExtractTable(sourcePath)); //run the extraction process in a thread for the UI to be more responsive
                }
                else
                {
                    MessageBox.Show("Source file doesn't exist.");
                }
            }
            else
            {
                MessageBox.Show("Please select the source file.");
            }
        }
        //This part concern the headers, rows and columns
        public async Task<string> ExtractTable(string sourcePath)
        {
            try
            {
                var doc = new HtmlAgilityPack.HtmlDocument();

                var converter = new MimeConverter(); //converter used to convert mhtml file to html

                if (File.Exists(ConvertedFileName))  //check if previously converted file is exist
                {
                    File.Delete(ConvertedFileName);  //delete the file
                }
                using (FileStream sourceStream = File.OpenRead(sourcePath))
                {
                    using (FileStream destinationStream = File.Open("page.html", FileMode.Create))
                    {
                        await converter.Convert(sourceStream, destinationStream);  //convert the file to html, it will be stored in the application folder
                    }
                }

                doc.Load(ConvertedFileName);  //load the html
                //var tables = doc.GetElementbyId("d19924139e528_grid"); //get the 7th table by its id, we can get the table id by inspecting element in the internet explorer
                var tables = doc.DocumentNode.SelectNodes("//table"); //get all the tables
                HtmlAgilityPack.HtmlNode table = null;


                if (tables.Count > 0)
                {
                    table = tables[tables.Count - 1]; //take the last table
                }


                if (table != null) //if the table exists
                {
                    dataGridView1.Invoke((Action)delegate //we use delegate because we accessing the datagridview from a different thread
                    {
                        this.dataGridView1.Rows.Clear();
                        this.dataGridView1.Columns.Clear();
                    });

                    var rows = table.SelectNodes(".//tr"); //get all the rows

                    var nodes = rows[0].SelectNodes("th|td"); //get the header row values, first item will be the header row always
                    string LifeLimitColumnName = ColumnsToSeparate.Where(c => nodes.Any(n => n.InnerText.ToLower().Contains(c))).FirstOrDefault();
                    if (string.IsNullOrWhiteSpace(LifeLimitColumnName))
                    {
                        LifeLimitColumnName = "Someunknowncolumn";
                    }
                    List<string> headers = new List<string>();
                    for (int i = 0; i < nodes.Count; i++) // LOOP
                    {
                        headers.Add(nodes[i].InnerText);
                        if (!nodes[i].InnerText.ToLower().Contains(LifeLimitColumnName))
                        {
                            dataGridView1.Invoke((Action)delegate
                            {
                                dataGridView1.Columns.Add("", nodes[i].InnerText);
                            });
                        }
                    }

                    int indexOfLifeLimitColumn = headers.FindIndex(h => h.ToLower().Contains(LifeLimitColumnName));
                    if (indexOfLifeLimitColumn > -1)
                    {
                        foreach (var eh in ExtraColumnsToAdd)
                        {
                            dataGridView1.Invoke((Action)delegate
                            {
                                dataGridView1.Columns.Add("", eh); //add extra header to the datagridview
                            });

                        }
                    }

                    int[] rowDataCount = new int[dataGridView1.Columns.Count];
                    Array.Clear(rowDataCount, 0, rowDataCount.Length);

                    for (int i = 1; i < rows.Count; i++) ///loop through rest of the rows
                    {
                        var row = rows[i];
                        var nodes2 = row.SelectNodes("th|td"); //get all columns in the current row
                        List<string> values = new List<string>(); //list to store row values
                        for (int x = 0; x < nodes2.Count; x++)
                        {
                            //rowes.Cells[x].Value = nodes2[x].InnerText;
                            string cellText = nodes2[x].InnerText.Replace("&nbsp;", " ");
                            if (!String.IsNullOrWhiteSpace(cellText)) {
                                rowDataCount[x]++;
                            }
                            values.Add(cellText); //add the cell value in the list

                        }
                        // Factory for -> Calendar, Flight Hours, Landings
                        if (indexOfLifeLimitColumn > -1)
                        {
                            values.RemoveAt(indexOfLifeLimitColumn);
                            string lifeLimitValue = nodes2[indexOfLifeLimitColumn].InnerText.Replace("&nbsp;", " ");
                            string[] splittedValues = lifeLimitValue.Split(' ');
                            for (int y = 0; y < ExtraColumnsToAdd.Count; y++)
                            {
                                if (ExtraColumnsToAdd[y] == "Calendar")
                                {
                                    string valueToAdd = string.Empty;
                                    string[] times = new string[] { "Years", "Year", "Months", "Month", "Day", "Days" };
                                    if (splittedValues.Any(s => times.Any(t => t == s)))
                                    {
                                        var timeFound = times.Where(t => splittedValues.Any(s => s == t)).FirstOrDefault();
                                        int index = splittedValues.ToList().FindIndex(s => s.Equals(timeFound));
                                        valueToAdd = $"{splittedValues[index - 1]} {timeFound}";
                                    }
                                    values.Add(valueToAdd);
                                }
                                else if (ExtraColumnsToAdd[y] == "Flight Hours")
                                {
                                    string valueToAdd = string.Empty;
                                    if (splittedValues.Any(s => s == "FH"))
                                    {
                                        int index = splittedValues.ToList().FindIndex(s => s.Equals("FH"));
                                        valueToAdd = $"{splittedValues[index - 1]} FH";
                                    }
                                    values.Add(valueToAdd);
                                }
                                else
                                {
                                    string valueToAdd = string.Empty;
                                    if (splittedValues.Any(s => s == "LDG"))
                                    {
                                        int index = splittedValues.ToList().FindIndex(s => s.Equals("LDG"));
                                        valueToAdd = $"{splittedValues[index - 1]} LDG";
                                    }
                                    values.Add(valueToAdd);
                                }
                            }
                        }

                        dataGridView1.Invoke((Action)delegate
                        {
                            this.dataGridView1.Rows.Add(values.ToArray()); //add the list as a row
                        });

                        int removedCount = 0;
                        for (int index = 0; index < rowDataCount.Length; index++) {
                            if (rowDataCount[index] == 0) {
                                dataGridView1.Invoke((Action)delegate
                                {
                                    this.dataGridView1.Columns.RemoveAt(index - removedCount);
                                    removedCount++;
                                });
                            }
                        }


                    }

                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            return string.Empty;
        }

        private void textBoxSourceFile_TextChanged(object sender, EventArgs e)
        {

        }

    }
}

这里是winform项目的设计代码

{
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
            this.textBoxSourceFile = new System.Windows.Forms.TextBox();
            this.btnBrowse = new System.Windows.Forms.Button();
            this.dataGridView1 = new System.Windows.Forms.DataGridView();
            ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
            this.SuspendLayout();
            // 
            // textBoxSourceFile
            // 
            this.textBoxSourceFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.textBoxSourceFile.Location = new System.Drawing.Point(51, 38);
            this.textBoxSourceFile.Margin = new System.Windows.Forms.Padding(4);
            this.textBoxSourceFile.Name = "textBoxSourceFile";
            this.textBoxSourceFile.Size = new System.Drawing.Size(903, 30);
            this.textBoxSourceFile.TabIndex = 0;
            // 
            // btnBrowse
            // 
            this.btnBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.btnBrowse.Location = new System.Drawing.Point(999, 38);
            this.btnBrowse.Margin = new System.Windows.Forms.Padding(4);
            this.btnBrowse.Name = "btnBrowse";
            this.btnBrowse.Size = new System.Drawing.Size(93, 28);
            this.btnBrowse.TabIndex = 1;
            this.btnBrowse.Text = "Browse";
            this.btnBrowse.UseVisualStyleBackColor = true;
            this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click);
            // 
            // dataGridView1
            // 
            this.dataGridView1.AllowUserToAddRows = false;
            this.dataGridView1.AllowUserToDeleteRows = false;
            this.dataGridView1.AllowUserToResizeRows = false;
            this.dataGridView1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.dataGridView1.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
            this.dataGridView1.BackgroundColor = System.Drawing.SystemColors.ControlLight;
            this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
            this.dataGridView1.Location = new System.Drawing.Point(51, 118);
            this.dataGridView1.Margin = new System.Windows.Forms.Padding(4);
            this.dataGridView1.Name = "dataGridView1";
            this.dataGridView1.RowHeadersVisible = false;
            this.dataGridView1.RowHeadersWidth = 62;
            this.dataGridView1.Size = new System.Drawing.Size(1042, 467);
            this.dataGridView1.TabIndex = 2;
            //this.dataGridView1.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellContentClick);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(1136, 636);
            this.Controls.Add(this.dataGridView1);
            this.Controls.Add(this.btnBrowse);
            this.Controls.Add(this.textBoxSourceFile);
            this.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
            this.Margin = new System.Windows.Forms.Padding(4);
            this.MinimumSize = new System.Drawing.Size(1086, 557);
            this.Name = "Form1";
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.Text = "Form1";
            ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.TextBox textBoxSourceFile;
        private System.Windows.Forms.Button btnBrowse;
        private System.Windows.Forms.DataGridView dataGridView1;
    }
}

当我 运行 它时,我有这个错误

click here to see the picture

可能你的数组中的列比你的网格多 - 在你声明数组后我看不到任何删除列的内容,但也许最好将删除列的键关闭是否实际的网格列有数据而不是你是否在其中放入任何数据的记忆。让我们问网格“对于每一列,该列的所有行都没有值吗?删除该列”:

dataGridView1.Invoke((Action)delegate
{
    var rowNumerable = dataGridView1.Rows.Cast<DataGridViewRow>();

    for (int i = dataGridView1.Columns.Count - 1; i >= 0; i--)
    {
        if (rowNumerable.All(r => string.IsNullOrEmpty(r.Cells[i].Value?.ToString())))
            dataGridView1.Columns.RemoveAt(i);
    }
});

旁注,我的列删除循环相反运行,因为这意味着删除列索引 i 仅影响列 > i,但我们已经处理了它们。它不会影响我们尚未处理的列索引的索引< i,因此我们不需要弄乱索引。

TLDR:如果要从正在循环的集合中删除内容,反向循环可以使事情变得更简单

终于搞定了,非常感谢大家。 Caius jayd 你是对的。我听从你的指示。它现在正在工作。这是代码:

                    dataGridView1.Invoke((Action)delegate
                    {
                        int[] rowDataCount = new int[dataGridView1.Columns.Count];
                        Array.Clear(rowDataCount, 0, rowDataCount.Length);

                        for (int row_i = 0; row_i < this.dataGridView1.RowCount; row_i++)
                        {
                            for (int col_i = 0; col_i < this.dataGridView1.ColumnCount; col_i++)
                            {
                                var cell = this.dataGridView1.Rows[row_i].Cells[col_i];
                                string cellText = cell.Value.ToString();
                                if (!String.IsNullOrWhiteSpace(cellText))
                                {
                                    rowDataCount[col_i] += 1;
                                }
                            }
                        }

                        int removedCount = 0;
                        for (int index = 0; index < rowDataCount.Length; index++)
                        {
                            if (rowDataCount[index] == 0)
                            {
                                this.dataGridView1.Columns.RemoveAt(index - removedCount);
                                removedCount++;
                            }
                        }
                    });
                }
            }```