Sharing Data with Multiple Windows Forms
Posted by Keith Elder | Posted in .Net, Programming, Smart Clients | Posted on 13-03-2006
I see this question a lot on forums, discussion boards and mailing lists. This question is typically asked in various ways. Here are a few examples:
- How do I access a varible in form2 from form1?
- How do I update a textbox field when a user clicks on a button in form1 to form2?
- How can form1 be updated with data from form2?
- How can I share data between two different windows forms?
Whatever the question is the underlying problem is still the same, getting something from A to B or B back to A. For a developer learning .Net and windows form programming the answer to these questions isn’t so obvious. Let’s take a look at sharing data such as a strong typed DataSet of Customers between two forms.
To start out with let’s look at the code of a newly created windows form:
namespace KeithElder
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
}
As we see code to a windows form is just an object. That means if we add a variable in this form that we want to share with another form we would have to make it a public variable. This is usually what developers try to do at first. Let’s try this approach first and see where it gets us.
namespace KeithElder
{
public partial class Form1 : Form
{
public CustomerDataSet Customers = new CustomerDataSet();
public Form1()
{
InitializeComponent();
}
}
}
Above we added a variable called customers that is public. This means it can be accessed outside of this form. If we create another form called Form2 though, how do we easily reference Form1? In other words we need to get the current running instance of Form1 so we can see the Customers public variable. Here is one way we could do this:
Form1 myForm = Application.OpenForms[“Form1”] as Form1;
This will grab the current open form Form1 and assign it to a variable called myForm. The first problem with this is we are boxing the Form1 object. This is costly overhead that we want to avoid. The other problem is, what if the user closed Form1? Or, what if they never opened Form1? How do we know? The answer is we could know, but that would cost us a lot of time developing that logic. All we REALLY want is the Customers data. We could care less about the form itself.
To solve this problem we can easily create a seperate object that both Form1 and Form2 can access. This allows us to get data from one location and increase our code reuse factor. You can call the object whatever you want and even put it wherever you want. I typically seperate these types of classes out into other class library projects. The reason is I don’t want any of the objects I reference tied to one single interface. In the example below I am going to call it “Global.cs”. Here is how that object would look.
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
namespace KeithElder
{
public static class Global
{
private static CustomerDataSet _customers = null;
public static CustomerDataSet Customers
{
get
{
if (_customers == null)
{
CustomerDataSetTableAdapters.CustomerTableAdapter ta = new DotNetPimps.CustomerDataSetTableAdapters.CustomerTableAdapter();
CustomerDataSet.CustomerDataTable dt = ta.GetData();
_customers = new CustomerDataSet();
_customers.Customer.Merge(dt);
}
return _customers;
}
}
}
}
Notice the class is marked public and static. This means we do not have to instantiate the class to use the class and we can access it publically in our namespace. There are also two static properties for our customers data. One is private and one is public. Having a private static variable allows us to check to see if this variable has ever been accessed and if not, go get the new data. Otherwise it will return the current data. You can think of this as sort of a Singleton pattern.
The last piece of the puzzle is how do we use this in our Form1 and Form2 scenario. Let’s look at the code for Form1. There isn’t any need to show Form2 since it will be the same. That’s the beauty of seperating the data out.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace KeithElder
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.customerDataGridView.DataSource = Global.Customers;
this.customerDataGridView.DataMember = “Customers”;
}
}
On Form_Load we retrieve the customer data and bind that to our DataGridView control. The same code would apply to Form2.
ee kaa thaa beee….!!!!