none
How do I pass Datatable to another form? RRS feed

  • Question

  • Newbie (3rd week of learning c#)

    I have a form with a datagridview, and the user selects a single record.

    In the ok_onclick function(method?) of the first form, I execute a query based on selection and place the entire row into a datatable. I can see the data so I know the query was successful.

    Now I need to open a second form and populate the textboxes on it with the contents of the datatable created by the ok_onclick function on the previous form.

    It appears I must add something in the second form's code in order to assign the datatable's values to each textbox.. but what and where?

    Wednesday, January 22, 2020 4:03 PM

Answers

  • I recommend that you don't speak of "DataTable" and "Form", otherwise an overzealous moderator will move your question to the Windows Forms forum.

    Instead, your question is actually "How do I pass a variable from one class to another class?" From the point of view of your C# code, the fact that the class happens to be a Form or the variable happens to be a DataTable is irrelevant. Any variable in any class would be passed in the same way.

    So, how do you pass the variable from class to class? Well, the "passing" has to be done by some piece of code that has access to both classes. One such piece of code would be your first class (the form that contains the datatable) at the point in which it creates the instance of the second class (the form where you want to read the datatable). One way to pass it is to pass it as an argument to the constructor:

    Form2 frm = new Form2(myDataTable); frm.Show();

    Of course, you would have to modify the constructor of the second class so that it accepts this argument and saves it in a class variable.

    Another way would be to declare a public property in the class and then assign the value to the property:

    Form2 frm = new Form2(); frm.MyProperty=myDataTable; form2.Show();

    Edit: Note that in the text above, the word "class" is used loosely; properly speaking, we are referring to an instance of a class.
    Wednesday, January 22, 2020 4:19 PM
    Moderator
  • Hello,

    In the following code sample I'm reading from a database table in a SQL-Server database, if using a different database simply change the data provider from SqlClient to OleDb for MS-Access etc.

    In the following class the connection is created via a library in my signature so : SqlServerConnection is from that library.

    public class DataOperations : SqlServerConnection

    In the class constructor those properties are from the library in my signature.

    public DataOperations()
    {
        DatabaseServer = ".\\SQLEXPRESS";
        DefaultCatalog = "MasterDetailSimple";
    }
    using System.Data;
    using System.Data.SqlClient;
    using BaseConnectionLibrary.ConnectionClasses;
    
    namespace ChildFormEdit_cs
    {
        public class DataOperations : SqlServerConnection
        {
            public DataOperations()
            {
                DatabaseServer = ".\\SQLEXPRESS";
                DefaultCatalog = "MasterDetailSimple";
            }
    
            public DataTable GetCustomers()
            {
                var dt = new DataTable();
    
                using (var cn = new SqlConnection { ConnectionString = ConnectionString })
                {
                    using (var cmd = new SqlCommand { Connection = cn })
                    {
    
                        cmd.CommandText =
                            "SELECT id,FirstName, LastName FROM MasterDetailSimple.dbo.Customer;";
    
                        cn.Open();
    
                        dt.Load(cmd.ExecuteReader());
    
                        dt.Columns["id"].ColumnMapping = MappingType.Hidden;
    
                    }
                }
    
                return dt;
    
            }
    
        }
    }

    Main form with DataGridView, one button. Note the BindingSource component is best for working with a DataGridView as we never have to touch the DataGridView once set to get data, in this case the current row.

    using System;
    using System.Data;
    using System.Windows.Forms;
    
    namespace ChildFormEdit_cs
    {
        public partial class Form1 : Form
        {
            private BindingSource _bindingSource = new BindingSource();
            private DataOperations _dataOperations = new DataOperations();
            public Form1()
            {
                InitializeComponent();
                Shown += Form1_Shown;
            }
    
            private void Form1_Shown(object sender, EventArgs e)
            {
                _bindingSource.DataSource = _dataOperations.GetCustomers();
                dataGridView1.DataSource = _bindingSource;
            }
    
            private void EditCurrentButton_Click(object sender, EventArgs e)
            {
                var row = ((DataRowView) _bindingSource.Current).Row;
    
                var editForm = new EditForm(row);
                if (editForm.ShowDialog() == DialogResult.OK)
                {
                    row.SetField("Firstname", 
                        editForm.DataRow.Field<string>("FirstName"));
    
                    _bindingSource.ResetCurrentItem();
                }
            }
        }
    }

    Edit form. What you don't see is the Cancel button DialogResult is set to Cancel in the property window for that button.

    using System;
    using System.Data;
    using System.Windows.Forms;
    
    namespace ChildFormEdit_cs
    {
        public partial class EditForm : Form
        {
            private DataRow _dataRow;
            public DataRow DataRow => _dataRow;
    
            public EditForm()
            {
                InitializeComponent();
                
            }
    
            public EditForm(DataRow dataRow)
            {
                InitializeComponent();
                _dataRow = dataRow;
                Shown += EditForm_Shown;
            }
    
            private void EditForm_Shown(object sender, EventArgs e)
            {
                FirstNameTextBox.Text = _dataRow.Field<string>("FirstName");
                LastNameTextBox.Text = _dataRow.Field<string>("LastName");
                Text = $"Current id {_dataRow.Field<int>("id")}";
            }
    
            private void UpdateButton_Click(object sender, EventArgs e)
            {
                if (!string.IsNullOrWhiteSpace(FirstNameTextBox.Text) || !string.IsNullOrWhiteSpace(LastNameTextBox.Text) )
                {
                    _dataRow.SetField("FirstName", FirstNameTextBox.Text);
                    _dataRow.SetField("LastName", LastNameTextBox.Text);
                    DialogResult = DialogResult.OK;
                    Close();
                }
                else
                {
                    MessageBox.Show("Both first and last name are required");
                }
            }
        }
    }

    EDIT

    Full source code is here with database scripts

    As you become more familiar with coding delegates/events can be used rather than passing a DataRow as I've done.


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange


    Wednesday, January 22, 2020 5:08 PM
    Moderator
  • In following your example, I do not understand the frm.MyProperty. Intellisense does not show that as an option.

    Well, of course Intellisense does not show that as an option. The idea is that instead of the word "MyProperty" you have to write there the real name that you gave to the property that you previously defined. If you did not do the work of defining a property in your class, then Intellisense will not know anything about your property. Remember from the text that you quoted: "...Another way would be to declare a public property in the class...". If you did not perform this first task, then of course the second part which depends on this one will not work.

    So, in the class where you want to receive the DataTable you write this:

    public DataTable MyProperty { get; set; }

    Of course, you wouldn't call it MyProperty; give it a name that makes sense for your program.

    • Marked as answer by J Vallee Thursday, January 23, 2020 2:03 PM
    Wednesday, January 22, 2020 7:16 PM
    Moderator

All replies

  • I recommend that you don't speak of "DataTable" and "Form", otherwise an overzealous moderator will move your question to the Windows Forms forum.

    Instead, your question is actually "How do I pass a variable from one class to another class?" From the point of view of your C# code, the fact that the class happens to be a Form or the variable happens to be a DataTable is irrelevant. Any variable in any class would be passed in the same way.

    So, how do you pass the variable from class to class? Well, the "passing" has to be done by some piece of code that has access to both classes. One such piece of code would be your first class (the form that contains the datatable) at the point in which it creates the instance of the second class (the form where you want to read the datatable). One way to pass it is to pass it as an argument to the constructor:

    Form2 frm = new Form2(myDataTable); frm.Show();

    Of course, you would have to modify the constructor of the second class so that it accepts this argument and saves it in a class variable.

    Another way would be to declare a public property in the class and then assign the value to the property:

    Form2 frm = new Form2(); frm.MyProperty=myDataTable; form2.Show();

    Edit: Note that in the text above, the word "class" is used loosely; properly speaking, we are referring to an instance of a class.
    Wednesday, January 22, 2020 4:19 PM
    Moderator
  • I recommend that you don't speak of "DataTable" and "Form", otherwise an overzealous moderator will move your question to the Windows Forms forum.

    Instead, your question is actually "How do I pass a variable from one class to another class?" From the point of view of your C# code, the fact that the class happens to be a Form or the variable happens to be a DataTable is irrelevant. Any variable in any class would be passed in the same way.

    So, how do you pass the variable from class to class? Well, the "passing" has to be done by some piece of code that has access to both classes. One such piece of code would be your first class (the form that contains the datatable) at the point in which it creates the instance of the second class (the form where you want to read the datatable). One way to pass it is to pass it as an argument to the constructor:

    Form2 frm = new Form2(myDataTable); frm.Show();

    Of course, you would have to modify the constructor of the second class so that it accepts this argument and saves it in a class variable.

    Another way would be to declare a public property in the class and then assign the value to the property:

    Form2 frm = new Form2(); frm.MyProperty=myDataTable; form2.Show();

    Edit: Note that in the text above, the word "class" is used loosely; properly speaking, we are referring to an instance of a class.

    Thank you for the heads up on class. That is a new concept for me.

    In following your example, I do not understand the frm.MyProperty. Intellisense does not show that as an option.

    Wednesday, January 22, 2020 5:07 PM
  • Hello,

    In the following code sample I'm reading from a database table in a SQL-Server database, if using a different database simply change the data provider from SqlClient to OleDb for MS-Access etc.

    In the following class the connection is created via a library in my signature so : SqlServerConnection is from that library.

    public class DataOperations : SqlServerConnection

    In the class constructor those properties are from the library in my signature.

    public DataOperations()
    {
        DatabaseServer = ".\\SQLEXPRESS";
        DefaultCatalog = "MasterDetailSimple";
    }
    using System.Data;
    using System.Data.SqlClient;
    using BaseConnectionLibrary.ConnectionClasses;
    
    namespace ChildFormEdit_cs
    {
        public class DataOperations : SqlServerConnection
        {
            public DataOperations()
            {
                DatabaseServer = ".\\SQLEXPRESS";
                DefaultCatalog = "MasterDetailSimple";
            }
    
            public DataTable GetCustomers()
            {
                var dt = new DataTable();
    
                using (var cn = new SqlConnection { ConnectionString = ConnectionString })
                {
                    using (var cmd = new SqlCommand { Connection = cn })
                    {
    
                        cmd.CommandText =
                            "SELECT id,FirstName, LastName FROM MasterDetailSimple.dbo.Customer;";
    
                        cn.Open();
    
                        dt.Load(cmd.ExecuteReader());
    
                        dt.Columns["id"].ColumnMapping = MappingType.Hidden;
    
                    }
                }
    
                return dt;
    
            }
    
        }
    }

    Main form with DataGridView, one button. Note the BindingSource component is best for working with a DataGridView as we never have to touch the DataGridView once set to get data, in this case the current row.

    using System;
    using System.Data;
    using System.Windows.Forms;
    
    namespace ChildFormEdit_cs
    {
        public partial class Form1 : Form
        {
            private BindingSource _bindingSource = new BindingSource();
            private DataOperations _dataOperations = new DataOperations();
            public Form1()
            {
                InitializeComponent();
                Shown += Form1_Shown;
            }
    
            private void Form1_Shown(object sender, EventArgs e)
            {
                _bindingSource.DataSource = _dataOperations.GetCustomers();
                dataGridView1.DataSource = _bindingSource;
            }
    
            private void EditCurrentButton_Click(object sender, EventArgs e)
            {
                var row = ((DataRowView) _bindingSource.Current).Row;
    
                var editForm = new EditForm(row);
                if (editForm.ShowDialog() == DialogResult.OK)
                {
                    row.SetField("Firstname", 
                        editForm.DataRow.Field<string>("FirstName"));
    
                    _bindingSource.ResetCurrentItem();
                }
            }
        }
    }

    Edit form. What you don't see is the Cancel button DialogResult is set to Cancel in the property window for that button.

    using System;
    using System.Data;
    using System.Windows.Forms;
    
    namespace ChildFormEdit_cs
    {
        public partial class EditForm : Form
        {
            private DataRow _dataRow;
            public DataRow DataRow => _dataRow;
    
            public EditForm()
            {
                InitializeComponent();
                
            }
    
            public EditForm(DataRow dataRow)
            {
                InitializeComponent();
                _dataRow = dataRow;
                Shown += EditForm_Shown;
            }
    
            private void EditForm_Shown(object sender, EventArgs e)
            {
                FirstNameTextBox.Text = _dataRow.Field<string>("FirstName");
                LastNameTextBox.Text = _dataRow.Field<string>("LastName");
                Text = $"Current id {_dataRow.Field<int>("id")}";
            }
    
            private void UpdateButton_Click(object sender, EventArgs e)
            {
                if (!string.IsNullOrWhiteSpace(FirstNameTextBox.Text) || !string.IsNullOrWhiteSpace(LastNameTextBox.Text) )
                {
                    _dataRow.SetField("FirstName", FirstNameTextBox.Text);
                    _dataRow.SetField("LastName", LastNameTextBox.Text);
                    DialogResult = DialogResult.OK;
                    Close();
                }
                else
                {
                    MessageBox.Show("Both first and last name are required");
                }
            }
        }
    }

    EDIT

    Full source code is here with database scripts

    As you become more familiar with coding delegates/events can be used rather than passing a DataRow as I've done.


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange


    Wednesday, January 22, 2020 5:08 PM
    Moderator
  • In following your example, I do not understand the frm.MyProperty. Intellisense does not show that as an option.

    Well, of course Intellisense does not show that as an option. The idea is that instead of the word "MyProperty" you have to write there the real name that you gave to the property that you previously defined. If you did not do the work of defining a property in your class, then Intellisense will not know anything about your property. Remember from the text that you quoted: "...Another way would be to declare a public property in the class...". If you did not perform this first task, then of course the second part which depends on this one will not work.

    So, in the class where you want to receive the DataTable you write this:

    public DataTable MyProperty { get; set; }

    Of course, you wouldn't call it MyProperty; give it a name that makes sense for your program.

    • Marked as answer by J Vallee Thursday, January 23, 2020 2:03 PM
    Wednesday, January 22, 2020 7:16 PM
    Moderator
  • Karen,Thank your for you code examples. I finally figured it out.

    I'm 3 weeks into what I estimate to be a a 2 year project, learning C# as I go.

    I have a fully developed app in another OOP database language and it took 18 months to write so I know this will take awhile.

    Thank you for your patience.


    Thursday, January 23, 2020 2:03 PM