.CSV到DataGridView行在VB.NET中出现空白

时间:2017-11-15 13:43:26

标签: sql vb.net csv datagridview

以下是我尝试导入VB.NET应用程序的CSV数据:

Raw Data

但是当我在应用程序中运行它时,它只会填充最后一行:

Output

以下是导入的代码:

Private Sub btnBrowse_Click(sender As Object, e As EventArgs) Handles btnBrowse.Click
    DataGridView1.ClearSelection()
    ofd.Filter = "(*csv)|*.csv"
    If ComboBox1.Text = "zVBImportTEST" Then
        If (ofd.ShowDialog() = DialogResult.OK) Then
            txtbxFilePath.Text = ofd.FileName
        End If
        Dim colsexpected As Integer = 6
        Dim thereader As New StreamReader(txtbxFilePath.Text, Encoding.ASCII)
        Dim sline As String = ""
        thereader.ReadLine()
        Do
            sline = thereader.ReadLine
            If sline Is Nothing Then Exit Do
            Dim words() As String = sline.Split(",")
            DataGridView1.Rows.Add("")
            For ix As Integer = 0 To 5
                DataGridView1.Rows(DataGridView1.Rows.Count - 1).Cells(ix).Value = words(ix)
            Next

        Loop
        thereader.Close()
    Else
        MessageBox.Show("Please select a project.", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
    End If
End Sub

我似乎无法弄清楚为什么其他行会出现空白。 如果有人能帮助我,我将不胜感激。

2 个答案:

答案 0 :(得分:1)

我不建议尝试通过StreamReader读取数据,而是在传递CSV文件的连接字符串时使用OleDb类。

以下是基于CSV文件内容返回DataTable的函数的快速示例:

Private Function ConvertCSVToDataTable(ByVal path As String) As DataTable
    Dim dt As DataTable = New DataTable()
    Using con As OleDb.OleDbConnection = New OleDb.OleDbConnection()
        Try
            con.ConnectionString = String.Format("Provider={0};Data Source={1};Extended Properties=""Text;HDR=YES;FMT=Delimited""", "Microsoft.Jet.OLEDB.4.0", IO.Path.GetDirectoryName(path))
            Using cmd As OleDb.OleDbCommand = New OleDb.OleDbCommand("SELECT * FROM " & IO.Path.GetFileName(path), con)
                Using da As OleDb.OleDbDataAdapter = New OleDb.OleDbDataAdapter(cmd)
                    con.Open()
                    da.Fill(dt)
                    con.Close()
                End Using
            End Using
        Catch ex As Exception
            Console.WriteLine(ex.ToString())
        Finally
            If con IsNot Nothing AndAlso con.State = ConnectionState.Open Then
                con.Close()
            End If
        End Try
    End Using

    Return dt
End Function

然后,您将如何绑定DataGridView:

DataGridView1.DataSource = Me.ConvertCSVToDataTable(ofd.FileName)

<强>更新

由于您要指定DataColumn的数据类型,请声明DataTable并将其分配给自定义函数,然后在事后进入并更改特定列的数据类型。这是一个快速(免费打字和未经测试)的例子:

Dim csv As DataTable = Me.ConvertCSVToDataTable(ofd.FileName)
With csv.Columns
    .Items(0).DataType = GetType(Int32)
    .Items(1).DataType = GetType(Int32)
    .Items(4).DataType = GetType(Int32)
    .Items(5).DataType = GetType(Int32)
End With

DataGridView1.DataSource = csv

答案 1 :(得分:0)

这是C#,但代码段显示了您当前正在做的事情,以及如何执行此操作。

using System.Collections.Generic;
using System.Windows.Forms;

namespace DataGridNoBinding_47308996
{
    public partial class Form1 : Form
    {

        DataGridView dgv = new DataGridView();
        public Form1()
        {
            InitializeComponent();
            dgv.Dock = DockStyle.Fill;
            dgv.AutoGenerateColumns = false;
            dgv.Columns.Add("Key","Key");
            dgv.Columns.Add("Value", "Value");
            this.Controls.Add(dgv);

            Dictionary<string, string> dgvdata = new Dictionary<string, string>();
            for (int i = 0; i < 10; i++)
            {
                dgvdata.Add($"key{i}", $"value{i}");
            }

            //AddToGridNoWork(dgvdata);
            AddToGridDoesWork(dgvdata);

        }

        /// <summary>
        /// This method does not work. This emulates what you are currently doing.
        /// </summary>
        /// <param name="dgvdata"></param>
        private void AddToGridNoWork(Dictionary<string, string> dgvdata)
        {
            foreach (KeyValuePair<string, string> item in dgvdata)
            {
                dgv.Rows.Add();
                dgv.Rows[dgv.Rows.Count - 1].Cells[0].Value = item.Key;
                dgv.Rows[dgv.Rows.Count - 1].Cells[1].Value = item.Value;
                dgv.Refresh();
            }
        }


        /// <summary>
        /// This method does work.
        /// Add a new row to the Grid and store the new row index in rowindex
        /// Then use the variable rowindex to update the correct row
        /// </summary>
        /// <param name="dgvdata"></param>
        private void AddToGridDoesWork(Dictionary<string, string> dgvdata)
        {
            foreach (KeyValuePair<string, string> item in dgvdata)
            {
                int rowindex = dgv.Rows.Add();
                dgv.Rows[rowindex].Cells[0].Value = item.Key;
                dgv.Rows[rowindex].Cells[1].Value = item.Value;
            }
        }
    }
}

在你的VB.net应用程序中,它可能只是做这样的事情

dim newRowIndex as Integer
newRowIndex = DataGridView1.Rows.Add("")
For ix As Integer = 0 To 5
    DataGridView1.Rows(newRowIndex).Cells(ix).Value = words(ix)
Next

改为使用DataDriver 这是我的代码,使用数据驱动程序而不是StreamReader重新旋转

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Data.OleDb;
using System.Data;

namespace DataGridNoBinding_47308996
{
    public partial class Form1 : Form
    {

        DataGridView dgv = new DataGridView();
        public Form1()
        {
            InitializeComponent();
            dgv.Dock = DockStyle.Fill;
            this.Controls.Add(dgv);

            Dictionary<string, string> dgvdata = new Dictionary<string, string>();
            for (int i = 0; i < 10; i++)
            {
                dgvdata.Add($"key{i}", $"value{i}");
            }

            //AddToGridNoWork(dgvdata);
            //AddToGridDoesWork(dgvdata);
            //AddToGridUsingDataDriver(@"M:\StackOverflowQuestionsAndAnswers\DataGridNoBinding_47308996\SampleData.csv");
            AddToGridByBindingTheWholeTable(@"M:\StackOverflowQuestionsAndAnswers\DataGridNoBinding_47308996\SampleData.csv");

        }

        /// <summary>
        /// This method will do what you want using a Data Driver instead of a StreamReader
        /// Though, this method binds the whole DataTable to the DataGridView instead of manually creating 1 row per data row
        /// </summary>
        /// <param name="dataFilePath"></param>
        private void AddToGridByBindingTheWholeTable(string dataFilePath)
        {
            dgv.AutoGenerateColumns = true;

            string connstring = $"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={System.IO.Path.GetDirectoryName(dataFilePath)};Extended Properties=\"Text;HDR=NO;FMT=Delimited\"";
            OleDbConnection conn = new OleDbConnection(connstring);
            OleDbCommand command = new OleDbCommand($"select * from {System.IO.Path.GetFileName(dataFilePath)}", conn);
            OleDbDataAdapter dataAdapter = new OleDbDataAdapter(command);
            DataTable dt = new DataTable();
            conn.Open();
            dataAdapter.Fill(dt);
            conn.Close();

            dgv.DataSource = dt;
        }



        /// <summary>
        /// This method will do what you want using a Data Driver instead of a StreamReader
        /// In this method, we are actively creating 1 DataGridRow for each DataRow in the DataTable
        /// </summary>
        /// <param name="dataFilePath"></param>
        private void AddToGridUsingDataDriver(string dataFilePath)
        {
            dgv.AutoGenerateColumns = false;
            dgv.Columns.Add("Key", "Key");
            dgv.Columns.Add("Value", "Value");

            string connstring = $"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={System.IO.Path.GetDirectoryName(dataFilePath)};Extended Properties=\"Text;HDR=NO;FMT=Delimited\"";
            OleDbConnection conn = new OleDbConnection(connstring);
            OleDbCommand command = new OleDbCommand($"select * from {System.IO.Path.GetFileName(dataFilePath)}", conn);
            OleDbDataAdapter dataAdapter = new OleDbDataAdapter(command);
            DataTable dt = new DataTable();
            conn.Open();
            dataAdapter.Fill(dt);
            conn.Close();

            if (dt != null && dt.Rows.Count > 0)
            {
                foreach (DataRow item in dt.Rows)
                {
                    int newrowid = dgv.Rows.Add();
                    dgv.Rows[newrowid].Cells[0].Value = item.Field<string>(0);
                    dgv.Rows[newrowid].Cells[1].Value = item.Field<string>(1);
                }
            }
            dgv.Refresh();
        }

        /// <summary>
        /// This method does not work. This emulates what you are currently doing.
        /// </summary>
        /// <param name="dgvdata"></param>
        private void AddToGridNoWork(Dictionary<string, string> dgvdata)
        {
            dgv.AutoGenerateColumns = false;
            dgv.Columns.Add("Key","Key");
            dgv.Columns.Add("Value", "Value");

            foreach (KeyValuePair<string, string> item in dgvdata)
            {
                dgv.Rows.Add();
                dgv.Rows[dgv.Rows.Count - 1].Cells[0].Value = item.Key;
                dgv.Rows[dgv.Rows.Count - 1].Cells[1].Value = item.Value;
                dgv.Refresh();
            }
        }


        /// <summary>
        /// This method does work.
        /// Add a new row to the Grid and store the new row index in rowindex
        /// Then use the variable rowindex to update the correct row
        /// </summary>
        /// <param name="dgvdata"></param>
        private void AddToGridDoesWork(Dictionary<string, string> dgvdata)
        {
            dgv.AutoGenerateColumns = false;
            dgv.Columns.Add("Key", "Key");
            dgv.Columns.Add("Value", "Value");

            foreach (KeyValuePair<string, string> item in dgvdata)
            {
                int rowindex = dgv.Rows.Add();
                dgv.Rows[rowindex].Cells[0].Value = item.Key;
                dgv.Rows[rowindex].Cells[1].Value = item.Value;
            }
        }
    }
}