I'm trying to pass values between a few winforms, I've got a total of 6 winforms, that the user will cycle through. I'm passing values between the forms using TextBox and Label Controls.
When I open the Primary winform, then click a button to load the second winform, everything works fine (I can pass values to the First Form). My problem is that once I direct the user to another form and this.Hide(); the current (2nd Winform) then try to use the Third form to pass values to the first, I get the following error:
Object reference not set to an instance of an object.
I'm confused because the control that the should be passing the value is passing the value to the first Form isn't NULL
I'm using the same code to connect all the forms together.
public MainForm MainForm;
Then I'm trying to pass the values like so:
MainForm.textBox1.Text = txt_FileName.Text;
Note: All the TextBox and Label controls that are passing values between the forms are public
Anyone run into this? Or any Ideas?
.
You need to make sure that all your forms are instantiated (through new MyForm1()...). Just declaring a variable of type MainForm won't create a form instance - you'll have to do it. My guess is that one of your forms is not created yet when you try to access a control.
This is yet another reason to not to use public controls (see my comment too), since the lifetime of your controls are tied to the lifetime of your form. It's better to hide controls from public access and send data to the form through data objects - the form will set all those values to its own controls. This also makes validation a lot easier, since a control's value can only be set to values allowed by the form. If you set control values from the outside, you'll have a tough time validating them in all scenarios.
I assume you're trying to use modal forms that work similar to a wizard where users go from one form to the next, following a clear path. If so, you can do something like this:
// Data class to set data in Form2
internal class Form2Data
{
public string Name;
...
}
...
internal class Form2 : Form
{
public static DialogResult ShowDlg ( Form2Data oData )
{
Form2 oFrm = new Form2 ();
oFrm.SetData ( oData );
DialogResult nResult = oFrm.ShowDialog ();
if ( nResult == DialogResult.Ok )
oFrm.GetData ( oData );
return ( nResult );
}
private void SetData ( Form2Data oData )
{
// Set control values here
}
private void GetData ( Form2Data oData )
{
// Read control values here
}
}
...
// You call this as such:
Form2Data oData = new Form2Data ();
oData.Name = "...";
DialogResult nResult = Form2.ShowDlg ( oData );
// after the call, oData should have updated values from Form2
if ( nResult == DialogResult.Ok )
{
// show your next form in a similar pattern - set up data
// call form's static method to pass it and then wait for
// the form to finish and return with updated data.
}
You'd have to use a similar pattern in your other forms, too. This does require more work since you need to set up a different data object for all the forms but this way you can easily do validation before and after the form is shown (in SetData and GetData). It also encapsulates your program better, since controls are not accessible from the outside.
.Net 2.0 and later has a feature for windows forms called the "default instance", where it gives you an instance with the same name as the type. The purpose of this feature is for compatibility with code migrated from old vb6 apps. If you're not migrating from an old vb app, it's usually better to avoid the default instances. They will get you in trouble, such as you have now. Instead, create a variable to hold form instances you construct yourself.
You should pass the value by using the instance value of the form.
for example:
SecondForm secForm2 = new SecondForm();
secForm2.textBox1.Text = txt_FileName.Text
so if you pass the value from SecondForm to ThirdForm:
ThirdForm thiForm = new ThirdForm();
thiForm.textBox1.Text = textBox1.Text
Related
I have a series of Windows Forms that act like a web based application. I have a form that sets a label's text to a random number and I'm trying to pass that number across other forms and be sure it updates everywhere. I don't have the ability to create a database, so that's why I'm doing that.
The issue I have is that when I move around the application and use a button to take me back to the first page that would get the random number, the code runs again and the number changes.
private void goToPage2_Click(object sender, EventArgs e)
{
this.Hide();
var form3 = new FORM3();
form3.ShowDialog();
this.Close();
}
I've commented out the Close and tried Show instead of ShowDialog, but the app crashes.
Basically I just need to figure out how to go about detecting if the form has already been created once in the application's life for that time and only have the random code run that time and not every time I come back to the page via just using the app like I want it used.
I'm using Windows Forms to save time as it's just for demonstrational purposes and don't want to deal with CSS and Bootstrap.
Thanks.
Run it in the Form's Shown event handler.
From the link:
The Shown event is only raised the first time a form is displayed
or the Load event handler.
From that link:
Occurs before a form is displayed for the first time.
Depending on when exactly you want it executed.
If you are creating new Forms every time and just want to know whether something happened during the course of the application execution - have a public static bool variable, set it when that code is executed, and check for it before that. Something like:
if(!Class1.theFlag)
{
Class1.theFlag = true;
//run your code here.
}
If you can't store variables in a database and need to pass those values amongst Windows Forms, simply add a new class to the project.
Name the class whatever you want. I named my class data as well as made it a static class.
Then add methods for get and set.
public static int someNum
{
get; set;
} = 0;
public static string someString
{
get; set;
} = "";
So, now you can just set those values to data.someNum or data.someString instead of having to check this or that. Much quicker than so many examples I've encountered here and much less code.
I would like to thank Ispiro for his educating me here though. Thanks man.
I'm really confused by now.
I've got a WinForm which holds a large Array
int[,] map = new int[1000, 1000];
I've also got a class containing a method "Draw".
The draw method now needs to get the value of a position in the array in the form. I tried doing the following thing:
In my Form class, I added
public int mapContentAtXY(Point mapPosition)
{
return map[mapPosition.X, mapPosition.Y];
}
Now if I try to perform
myInt = Ingame.mapContentAtXY(myPoint);
//Note: Ingame is the name of my Form
It says
Error 2 'Neu.Ingame' does not contain a definition for 'mapAtPositionXY'
This is really confusing, I just added that definition, it's also set as public. So why the hell doesn't it work?
You will need to pass the instance of the Form to the draw-class by using this when you create or call that instance of the draw-class. Then you can access that method through that form instance.
OR
Store the map not in the form, but in that draw-class. Move the mapContentAtXY method to the draw-class. Use the one instance of the draw-class in your form to update that map.
Your method mapContentAtXY is an instance method.
Change Ingame to this, if you're calling it from within your form instance.
myInt = this.mapContentAtXY(myPoint);
Otherwise use the form instance
myInt = frmInGameInstance.mapContentAtXY(myPoint);
This question already has answers here:
Communicate between two windows forms in C#
(12 answers)
Closed 3 years ago.
I have a table named questions with a field name qcategory. In WFA I have a ToolStripMenu where I have a category named Simulation and a sub-category named B. So, I want to create a mysql SELECT where to select only rows which values are equal with sub-category value. (Columns qcategory from table has value B). This is the string:
static string dataA = "SELECT DISTINCT * FROM questions order by rand() limit 1";
The only problem is that I have 2 forms. One with menu and one where I want to make that select.
You should try to split your UI-code and your database code. This is called Layering (MVVM, MVC, MVP,...) but you don't have to!
There are several ways:
1) Make a class that both forms can reference and execute your database logic there. (that would be the cleanest way for now)
2) Create an Event in your Form with the menu and react on it in the other Form
3) Your menu Form holds a reference to the other Form and executes a Method on it passing the selected subitem.
In code
1
public static class SqlClass
{
public static void ExecuteQuery(string menuItem)
{
//execute query
}
}
Form 1
//menu changed...
SqlClass.ExecuteQuery(menuItem)
2
Form1:
public event EventHandler<string> MenuItemChanged;
//menu changed...
if(this.MenuItemChanged != null)
this.MenuItemChanged(this, menuitem)
Form2:
public Form2(Form1 otherForm)
{
InitializeComponent();
_otherForm.MenuItemChange += //... handle your sql code
}
3
private readonly Form2 _otherForm;
public Form1(Form2 otherForm)
{
InitializeComponent();
_otherForm = otherForm;
}
//menu changed...
otherForm.ExecuteQuery(menuitem);
For the examples, Form 2 is the form where you want to execute your query because there is the Method/Event-Handler defined that will interact with your database.
To understand the solution, you need a more high level perspective - you get an information in code behind of a Form (a Class) and you want to consume that information somewhere else.
In general you need a reference to the Form that holds the information you are interested in and it tells you the information when changed (Event) OR
the information source tells every interested destination (calls a Method). Then the Information source hold the references to the consumers.
Both concepts are the same just the direction of the communication (and reference) changes.
The alternative (Option 1) is that you move your information destination somewhere else (e.g. in a static class) and consume it there. The Mechanism of passing the information is pretty much the same (via a parameterized Method call) but it encapsulates the UI-colde (Form) from the Database code (SQL query execution)
Environment: Visual Studio 2008, C#, SQL Server, Windows development, Multiuser, New Developer
I have a method in form A that I use to display textbox information there.
Also I have a button that displays another form when clicked (form B).
Form B is created with frm.ShowDialog();
Form B has the same textboxes on it with the same names, they are identical (copied and pasted from form A)
I want to use the method in Form A to display the information in Form B, rather than copying and pasting the method from form A into form B
I made the method in form A public and called it from from B but nothing displays in form B's textboxes. Why? I don't get any errors.
Should I keep it simple and put a copy of form A's method in Form B instead of calling the method in form A from form B? That's the only way I can get it to work.
Form A is for displaying customer information, Form B is for editing customer information.
I'm passing and returning information between the forms and that's all working.
The forms are not identical, i.e., form B doesn't have textbox for the customer's notes, they are edited in a separate form.
Thank you for your input.
you should use an info class and retrieve data from it both in form A and form B
don't use duplicate code, just use another class for logic \ info.
You can read more about it here
Make a model class whose members represent the data to be shown in both forms. In visual studio 2008 I believe there is support to create a project data source based on an object. Create the data source from your model class. Then, in both forms, add a binding source. Set the data type for the source to be the project data source. Then, the designer will let you select bindings for each control from the binding source. Finally, in the form's constructor, accept a model class instance, and set the binding source's data source to be that instance.
Even if you have the same textboxes with same names when you call formA you are just changing the instance of formA which means only the textboxes in formA are changed.
You have to understand that every class has its own instance separate from the other.
That does not mean though that you cannot access formB textboxes in formA. I can see that you want to consolidate; if I'm not mistaken what you have in formA method is something like:
public void methodA(Customer customer)
{
textboxName = customer.Name;
textboxAddress = customer.Address;
}
If you dont want to duplicate this then the other approach that I can think of is:
1.) Create an interface for all the duplicate properties.
public interface ICustomerForm
{
string Name {get; set;}
string Address {get; set;}
}
2.) Have the 2 forms implement the interface.
public class FormA : Form, ICustomerForm
{
public string Name
{
get
{
return _textBoxName.Text;
}
set
{
_textBoxName.Text = value;
}
}
}
Do the same for formB
3.) Create a static helper class where you just pass the customer class. e.g:
public static class FormHelper
{
public static UpdateCustomerInfo(ICustomerForm form, Customer customer)
{
form.Name = customer.Name;
form.Address = customer.Address;
}
}
4.) In your two forms just call the helper class and pass itself as the first parameter and the customer class as the second parameter.
//Method in formA
public void formA()
{
FormHelper.UpdateCustomerInfo(this, customer);
}
//Method in formB
public void formB()
{
FormHelper.UpdateCustomerInfo(this, customer);
}
This way you just have one line of code in your forms and the setting of info is on the consolidated helper class.
How can I update and get values in a Windows Forms application while moving one form to other form (like cookies)?
I need to update the values to some variable and again I am going to refer stored values and need to do some calculations.
I have used cookies in ASP.NET but I am not able to find out the same concept in .NET Windows Forms (C#).
How can these issues be resolves?
You can use object references.
You can decalre a read/write Property for each variable you want to be available in another form and the use them for sharing your data.
One way to do this is to declare variables to be public, either in a global module or in any form.
public x as double
If it is declared in a module, you can access it with the variable name only. To access data declared in another form, use that form name with the variable: form1.x = 7
Another way is to declare a property in a form or other class.
A really simple way of getting cookie-like functionality would be to declare a static string dictionary in Program (Program.cs)
public static System.Collections.Specialized.StringDictionary SortOfLikeCookies = new System.Collections.Specialized.StringDictionary(); and read/write string values using Program.SortOfLikeCookies["Name"] = "Value";