Scoping variables 'globally'?

Gladimir

Regular
Joined
Mar 29, 2003
Messages
60
Location
San Diego, CA
I have created the public class fileInfo with two properties; 1) PathName and 2) FileName.

I have two buttons on form Main, buttonSetFile and buttonTable. The click event for buttonSetFile allows the end-user to select a database file using openFileDialog1 (see code below).

C#:
private void buttonSetFile_Click(object sender, System.EventArgs e)
{
   switch (openFileDialog1.ShowDialog())
   {
      case DialogResult.OK:
         fileInfo dbInfo = new fileInfo();
         dbInfo.PathName = openFileDialog1.FileName;
         labelDatabaseName.Text = dbInfo.FileName;
         buttonTable.Enabled = true;
         break;
      case DialogResult.Cancel:
         break;
   }
}

I want to read the PathName and the FileName from the buttonSetFile click event in the buttonTable click event. In fact, I want to pass the PathName and FileName values to a new form made available to the end-user in the buttonTable click event.

How/Where do I instantiate a fileInfo object to make the PathName and FileName properties available from all control events or even from another form?
 
Right below the class declaration is where you would normally put it. Declare it as static if you want other forms to access it.

Ex:
public static FileInfo dbInfo = null;

However, you can put it anywhere in your code as long as it is outside all blocks except the class block and namespace block.
 
Very Cool, Thanks.

It is now working, though not with the 'null' syntax. I actually had to go ahead an declare dbInfo as a 'new' FileInfo object.

Thanks again.
 
Another idea would be to pass the path information to the new form through the new form's constructor. You can certainly make the variable static, though it's not as "clean" since the popup form now has to know about the other form to get to the exposed static field/property.

The reason null didn't work for you is probably because you didn't set it to "new ...()" in your buttonSetFile_Click event. You can declare the variable with new, as it sounds like you did, but then you'll always have this instance even if you've never set the properties. Again, it might be "cleaner" to set it to new only when you need it, if you really do need it. I'd stick with using the constructor idea mentioned above though. Better to learn how to use it now as you'll need to learn it sooner or later (plus it's the better way to code).

-Nerseus
 
Better to learn how to use it now as you'll need to learn it sooner or later (plus it's the better way to code).

Great! That's why I'm here. Let's start with the why the 'null'
declaration throws a null exception when I try to read the dbInfo.PathName
property.

C#:
static void Main()
{
   Application.Run(new formMain());
}

// line recommended by aewarnick
public static FileInfo dbInfo = null;

private void buttonSetFile_Click(object sender, System.EventArgs e)
{
   switch (openFileDialog1.ShowDialog())
   {
      case DialogResult.OK:
         // this line throws null exception
         dbInfo.PathName = openFileDialog1.FileName;
         labelDatabaseName.Text = dbInfo.FileName;
         buttonTable.Enabled = true;
         break;
      case DialogResult.Cancel:
         break;
   }
}

You're correct in that I do not want objects being created if they're never going to be used. For our immediate purposes, what changes would I have to make to get this to work 'as is'?

Next, let's explore your first suggestion. I would like to display formTables in the click event of buttonTables. On formTables, I would like to use dbInfo.PathName in the connection string of my connection object.

Let's say I don't make my dbInfo static. In that case, dbInfo will be created as a new instance of FileInfo in the buttonSetFile click event. The user now clicks buttonTable to bring up formTables.

How does the dbInfo.PathName persist to the buttonTable click event and then to formTables?

Thanks for any help you can give.
 
To get around the null reference exception, you want to create an instance of FileInfo before you use it. You could, for example, do this:
C#:
private void buttonSetFile_Click(object sender, System.EventArgs e)
{
   switch (openFileDialog1.ShowDialog())
   {
      case DialogResult.OK:
         // this line throws null exception
         [b]dbInfo = new FileInfo();[/b]
         dbInfo.PathName = openFileDialog1.FileName;
         labelDatabaseName.Text = dbInfo.FileName;
         buttonTable.Enabled = true;
         break;
      case DialogResult.Cancel:
         break;
   }
}

This only creates the object when you need it - after they've chosen a file through the dialog.

The other option has been discussed *many* times on this forum. The main problem is that in .NET, you no longer have a built-in reference to a form as you did in VB6. In VB6 it was standard practice to put public properties on a form and access those properties anywhere else in code, including other forms.

In .NET, it's cleaner to pass in data through the constructor. Let's say your popup form is called formPopup (the class name that is). Here's how you might create it:
C#:
public class formPopup : Form
{
   private string filename = string.empty;

   public formPopup(string filename)
   {
      this.filename = filename;
   }
}

This defines the formPopup class to have only one constructor which takes a string. It then saves the filename in a private variable in case you need it later.

Now in your formMain, you need to pass the filename to the popup form. Here's how you might do this:
C#:
private void buttonSetFile_Click(object sender, System.EventArgs e)
{
   switch (openFileDialog1.ShowDialog())
   {
      case DialogResult.OK:
         // this line throws null exception
         labelDatabaseName.Text = openFileDialog1.FileName;
         buttonTable.Enabled = true;
         formPopup frm = new formPopup(openFileDialog1.FileName);
         frm.ShowDialog();
         break;
      case DialogResult.Cancel:
         break;
   }
}

Obviously I don't know what you really need, but that shows how you could create a new formPopup and pass in the filename that was selected.

With this scenario, you don't want your FileInfo dbInfo variable at all. If formMain really needs the filename outside of the button click event, I'd store it in a string.

-Nerseus
 
Brilliant!

Wonderful! I greatly appreciate all your help.

I replaced the FileInfo class with a public static string, which would not be necessary in your implementation; but I want to cling to the separation of the buttonSetFile click event and the buttonTables click event.

I remain under the assumption that a static string is still necessary to pass the filename string returned by openFileDialog1 in the buttonSetFile click event as a parameter to the new formTables object in the buttonTables click event.

My last step is figuring out how to return the tables selected on formTables back to formMain. It should be smooth sailing form there...

Thanks again for all your help.
 
First, you don't need to make the string filename static. You can simply make it private and set it in buttonSetFile and use the value (to pass to formTables) in buttonTables_click. If you want to get fancy, name the variable something like _filename and add a private property to your form named Filename. In the "Set" portion of the property, you can enable the buttonTables button if the Value.Length > 0 (not an empty string). That way you can handle enabling/disabling buttonTables - assuming you want it disabled until they pick a file.

To get the tables selected from formTables is simple. Expose whatever it is you "select" on formTables as a public field (variable or property). Set that property on formTables just before you close the form. Then on formMain, you can read the property and do what you need with it.

For example, suppose you want formTables to "return" an array of strings that are the table names. On formTables, add the following:
C#:
// Put this at the top, as a public field
public string[] Tables;

private void btnOk_Click(object sender, System.EventArgs e)
{
	Tables = new string[listBox1.SelectedItems.Count];
	for(int i=0; i<listBox1.SelectedItems.Count; i++)
		Tables[i] = listBox1.SelectedItems[i].ToString();

	this.DialogResult = DialogResult.OK;
	this.Close();
}

Then in formMain:
C#:
private void btnShowTables_Click(object sender, System.EventArgs e)
{
	formTables frm = new formTables(filename);
	frm.ShowDialog();
	if(frm.DialogResult==DialogResult.OK)
	{
		foreach(string s in frm.Tables) ...
	}
	frm.Dispose();
}

-Nerseus
 
Back
Top