0

Everything in my project is mostly dynamic and I am having a little issue when trying to create multiple datagridviews dynamically

Currently with my setup I am getting a NullReferenceError on this line dgv.DataSource = ds.Tables[index.ToString()];

Ive tried several different approaches but to my knowledge I cant seem to find anything wrong with my code this should be working perfectly

all the relevant code is below

//Create a new window
private void NewWindow() {
            TabPage tb = new TabPage();
            DataGridView dgv = new DataGridView();
            DataTable dt = new DataTable();

            tb.Text = "New..";
            dgv.Dock = DockStyle.Fill;

            tb.Controls.Add(dgv);
            tabControl1.TabPages.Add(tb);
}

//bind
DataGridView dgv = tabControl1.SelectedTab.Controls.OfType<DataGridView>() as DataGridView;
dgv.DataSource = ds.Tables[index.ToString()];

EDIT: Here all all the relevant functions and variables

DataSet ds = new DataSet();

        string path = "";

        bool _exiting = false;

        private void openToolStripMenuItem_Click(object sender, EventArgs e) {
            Browse();
        }

private void NewWindow() {
            TabPage tb = new TabPage();
            DataGridView dgv = new DataGridView();
            DataTable dt = new DataTable();

            tb.Text = "New..";
            dgv.Dock = DockStyle.Fill;

            tb.Controls.Add(dgv);
            tabControl1.TabPages.Add(tb);
        }

        private void OnColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) {
            int index = tabControl1.SelectedIndex;
            EditHeader eh = new EditHeader(this.UpdateHeader);
            eh.TextBox1.Text = ds.Tables[index.ToString()].Columns[e.ColumnIndex].ToString();
            eh.TextBox2.Text = e.ColumnIndex.ToString();
            eh.Show();
        }

        private void UpdateHeader(string indexVal) {
            string[] array = indexVal.Split(',');
            int index = int.Parse(array[0]);
            ds.Tables[index.ToString()].Columns[index].ColumnName = array[1];
            DisableSortMode();
        }

        private void OpenCSVFile() {
            using (TextFieldParser csvParser = new TextFieldParser(path)) {
                csvParser.TextFieldType = FieldType.Delimited;
                csvParser.SetDelimiters(",");

                int index = tabControl1.SelectedIndex;

                bool firstLine = true;

                while (!csvParser.EndOfData) {
                    //proccessing
                    string[] fields = csvParser.ReadFields();

                    if (firstLine) {
                        foreach (var val in fields) {
                            ds.Tables[index.ToString()].Columns.Add(val);
                        }

                        firstLine = false;

                        continue;
                    }
                    //get row data
                    ds.Tables[index.ToString()].Rows.Add(fields);
                }

                //bind
                DataGridView dgv = tabPage1.Controls.OfType<DataGridView>() as DataGridView;
                dgv.DataSource = ds.Tables[index.ToString()];
            }
        }

        private void Browse() {
            OpenFileDialog csvSearch = new OpenFileDialog();
            csvSearch.Filter = "csv files (*.csv)|*.csv";
            csvSearch.FilterIndex = 1;
            csvSearch.Multiselect = false;

            if (csvSearch.ShowDialog() == DialogResult.OK) {
                int index = tabControl1.SelectedIndex;
                DataTable dt = ds.Tables.Add(index.ToString());
                path = csvSearch.FileName;
                tabPage1.Text = csvSearch.FileName;
                OpenCSVFile();
                DisableSortMode();
            }
        }
FlamingGenius
  • 216
  • 2
  • 20

1 Answers1

1

The problem is this line:

DataGridView dgv = tabPage1.Controls.OfType<DataGridView>() as DataGridView;

In this context, the OfType method will return an IEnumerable<DataGridView>. When you cast it to DataGridView using as, the result will be null, since it's the wrong type (there is no implicit cast between a type and an enumerable of that type). This is true, by the way, of most LINQ operations, which generally work with sets and not instances.

If you want to get the single instance from the set, you can use:

DataGridView dgv = tabPage1.Controls.OfType<DataGridView>().Single();

...or possibly:

DataGridView dgv = tabPage1.Controls.OfType<DataGridView>().First();

...if you expect there will be more than one DataGridView and you just want one of them.

The as portion should not be needed since OfType<T>.Single() returns a T already (it implicitly calls Single<DataGridView>()). Same for First().

John Wu
  • 44,075
  • 6
  • 37
  • 69