Jack
Jack

Reputation: 17

Sending data between 2 forms

I have form1 with datagridview and a button. When i click a button, a new form opens up where there is a textbox and also a button. In this textbox i can write query and with a click of a button query results are shown in form1 datagridview. The problem is that it opens up another instance of form1 , but i would like that form1 stays open the whole time and only records in datagridview are changing, according to the query input in form2. Both form1 and form2 needs to be opened and active when called.

Here is my code:

//FORM 1
public Form1()
{
    InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
    var queryForm = new Form2();
    queryForm.Show(this);
}

//FORM 2
public Form2()
{
    InitializeComponent();
}

private SqlConnection Conn;

private void Form1_Load(object sender, EventArgs e)
{
    Conn = new SqlConnection(@"Data Source=srvr;Initial Catalog =db; User ID =user; Password =pass");


}

private void btnExecute_Click(object sender, EventArgs e)
{
    Form1 frm1 = new Form1();
    frm1.Show(this);
    frm1.Activate();

    SqlCommand cmd = new SqlCommand();
    cmd.Connection = Conn;
    cmd.CommandText = txtQuery.Text;

    try
    {
        Conn.Open();

        SqlDataReader reader = cmd.ExecuteReader();

        frm1.dataGridView1.Columns.Clear();
        frm1.dataGridView1.Rows.Clear();
        if (reader.HasRows)
        {
            DataTable schema = reader.GetSchemaTable();
            int field_num = 0;
            foreach (DataRow schema_row in schema.Rows)
            {
                int col_num = frm1.dataGridView1.Columns.Add(
                    "col" + field_num.ToString(),
                    schema_row.Field<string>("ColumnName"));
                field_num++;

                frm1.dataGridView1.Columns[col_num].AutoSizeMode = 
                    DataGridViewAutoSizeColumnMode.AllCells;
            }

            object[] values = new object[reader.FieldCount];

            while (reader.Read())
            {
                reader.GetValues(values);
                frm1.dataGridView1.Rows.Add(values);
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("Error executing command.\n" + ex.Message);
    }
    finally
    {
        Conn.Close();
    }
}

Upvotes: 0

Views: 131

Answers (2)

Rand Random
Rand Random

Reputation: 7440

Well, since you are calling Form1 frm1 = new Form1(); - what else did you expect than opens up another instance of form1 ? - Why should new Form1() not produce another instance?

You will need to get the reference of the already created Form1.

See this for example Find the open forms in c# windows application

When you found it you can activate it for example:

var frm1 = Application.OpenForms[0];
//frm1.Show(this); <- don't need to call Show since its already open
frm1.Activate();

Also you should change your btnExecute_Click to this.

private void btnExecute_Click(object sender, EventArgs e)
{
    var frm1 = Application.OpenForms[0] as Form1; //find `Form1` like you want, I only take [0]

    //always create a new instance of SqlConnection here and dispose it with the using Keyword
    //don't use a private field to try to keep the Connection, let the internal Connection pool handle that case
    using (var con = new SqlConnection(@"Data Source=srvr;Initial Catalog =db; User ID =user; Password =pass"))
    {
        try
        {
            con.Open();

            //clean up, Command/Reader with using keyword
            using (var cmd = con.CreateCommand())
            {
                cmd.CommandText = txtQuery.Text;
                using (SqlDataReader reader = cmd.ExecuteReader())
                {
                    //read data
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error executing command.\n" + ex.Message);
        }
    }

    //should activate the `Form1` AFTER the job is done, you can consider if you only want to activate it if the previous Code didn't fail
    frm1.Activate();
}

Don't really get what you are doing in your "read_data" routine.

This Code block:

frm1.dataGridView1.Columns.Clear();
frm1.dataGridView1.Rows.Clear();
if (reader.HasRows)
{
    DataTable schema = reader.GetSchemaTable();
    int field_num = 0;
    foreach (DataRow schema_row in schema.Rows)
    {
        int col_num = frm1.dataGridView1.Columns.Add(
            "col" + field_num.ToString(),
            schema_row.Field<string>("ColumnName"));
        field_num++;

        frm1.dataGridView1.Columns[col_num].AutoSizeMode = 
            DataGridViewAutoSizeColumnMode.AllCells;
    }

    object[] values = new object[reader.FieldCount];

    while (reader.Read())
    {
        reader.GetValues(values);
        frm1.dataGridView1.Rows.Add(values);
    }
}

Try if the following is sufficient, replace my comment "//read data" in the above code with this:

frm1.dataGridView1.AutoGenerateColumns = true; //say to automatically create columns, based on the result inside the datatable
frm1.dataGridView1.Columns.Clear();
var dataTable = new DataTable();
dataTable.Load(dataReader); //load the SqlDataReader into the DataTable
frm1.dataGridView1.DataSource = dataTable; //set the dataGridView's DataSource to the dataTable

Upvotes: 0

Sparsha Bhattarai
Sparsha Bhattarai

Reputation: 703

On button click in form1, you can simply open a new instance of form2 and do your work there and on closing receive that value in form1. Or you can pass the instance of your form1 into form2 via constructor and update form1 from form2. For example:

var isFormClosed = false;
using(form1 frm = new form1())
{
   // do something here
   frm.ShowDialog();
   isFormClosed = true;
}

Or, if you prefer to pass the reference of form1 into form2,

var isFormClosed = false;
using(form1 frm = new form1(this))
{
   // do something here
   frm.ShowDialog();
   isFormClosed = true;
}

Here, in form2, you can simply use the passed reference of form1 to update properties or grids.

Upvotes: 0

Related Questions