Passing data w/ constructor with main form - c#

I have three forms, f1, f2, f3 we'll call them. I have a class Account, in which I store username, password, groups and path (files). F2 is the main form, and should interact with both other forms. F1 is the login form and F3 is the edit form. I use this in my program.cs to call the login form before other forms.
Form1 login = new Form1();
if (login.ShowDialog() == DialogResult.OK)
{
Application.Run(new Form2());
}
To pass data between f2 and f3, I use a constructor with the account class. However, I would also like to pass data from f1 to f2, but if I use the same approach, I get no data interaction between the forms (data is null).
I edited the above code to this:
Form1 login = new Form1();
Account acc = new Account();
if (login.ShowDialog() == DialogResult.OK)
{
Application.Run(new Form2(acc));
}
In the login form (f1), I pass some data to the Account class, so upon login button click this happens:
private void LoginButton_Click(object sender, EventArgs e)
{
Account acc = new Account();
//some code
acc.Groups = "New group";
//some more code
DialogResult = DialogResult.OK;
}
Then, in the Form2.cs, I have the following code:
string groups = "";
public Form2(Account acc)
{
InitializeComponent();
groups = acc.Groups;
}
But whenever I run it like that, I never get any results in the main form (f2), acc.Groups is always null, and I do not know why exactly. I used the same approach with constructors to pull data from f2 to f3, and it worked fine, why doesn't this work? Is it because I use the wrong approach with the login form? What is the correct way to handle this?

the problem is that you create a new instance of Account in the LoginButton_Click event. and you never pass this instance to the form2!
Create a field in the Form1 class of type Account:
Account my_account;
And overload the constructor to take an account as parameter:
public Form1(Account acc)
{
my_account = acc;
}
then reference in the click event the field my_account
private void LoginButton_Click(object sender, EventArgs e)
{
//reference the class variable
my_account.Groups = "New group";
//some more code
DialogResult = DialogResult.OK;
}
In the beginning you need to pass the starting instance of Account into the Form1 constructor so it can be filled with values:
Account acc = new Account();
Form1 login = new Form1(acc);
if (login.ShowDialog() == DialogResult.OK)
{
Application.Run(new Form2(acc));
}
Explanation in detail:
When creating an instance of Account acc = new Account(); you get a unique object with a specific location in the memory. When you pass this object to the constructor of Form1 and assign it to the private field my_account you actually pass only the reference of acc. Meaning that you pass the location of it in memory. That means that when you do this: my_account = acc; in the constructor you make sure that my_account points to the same location as the acc object. When you manipulate values of my_account by assigning a string to Groups you actually manipulate the original acc object. After returning from Form1 you pass the acc object again as reference to the next constructor. So when you access in Form2 this object in groups = acc.Groups; you access the original location in memory that you have manipulated and to which you have assigned the string "New group".
In your posted code you created in Form1 an entire new object using Account acc = new Account(); which is again unique and independent of the object that you created in the very beginning. This object also is located on a different portion of memory as the first acc object. This is why the property Groups is null when you have tried to access it in Form2
I hope this is understanable

I see you create new Account() in two places ( so you have more than one instance), but you don't pass account to form2 nowhere.
You can make Account static like Janes suggest in comment or make property to get account.

In Form1, declare
public Account Account { get; set; }
In Account, declare
public Form1 Form1{ get; set; }
After created 2 objects login and acc :
Form1 login = new Form1();
Account acc = new Account();
Assign to each other
login.Account = acc;
acc.Form1 = login;

Related

How do i send a value from my first form to my main form in c#

Im making a little log in interface and im trying to send the user id after a succesfull login to my main form for safekeeping. I know how to do it from main to a secondary but i have no idea how to do it back. as im not creating a new Form main = new form();
public void btnLogIn_Click(object sender, EventArgs e)
{
UserClass existingUser = new UserClass();
existingUser.username = tbUsername.Text;
existingUser.password = tbPassword.Text;
result = databaseConnector.LogUSerIn(existingUser.username, existingUser.password);
if (result == 0)
{
MessageBox.Show("There aren't any registerd users with these credentials. Please try again or register below");
}
else
{
MessageBox.Show("Log in succesfull, Happy browsing!");
//Return value to Main form.
LogIn.ActiveForm.Close();
}
I would like the value result be send back to my main form. ive browsed the internet for about half an hour now and i only see from MAIN to SECONDARY but i can never find the reversed.
You can do it in a similar way like the OpenFileDialog does it.
Create a public property UserId in your login form and set the user id when the user logs in.
You can now access this property UserId in your main form after the ShowDialog() method of your login form has been called.
I can look something like this in your main form:
var loginForm = new LoginForm();
loginForm.ShowDialog();
var userId = loginForm.UserId;
// do something with the userId. maybe store it in a property of your main form.

Calling a constructor not filling textbox fields of already opened form?

I am developing an application where i have to get data from 2 different forms to fill different fields of same form
My Work
I have called the constructor of form1 from party form and from itemform with parameters
code form Itemform
string units = dr.Cells[2].Value.ToString();
string rate = dr.Cells[3].Value.ToString();
Form1 f1 = new Form1( units, rate);
this.Hide();
constructor on form1 called while debugging
public Form1(string units, string rate)
{
InitializeComponent();
ItemId_LBL.Text = units;
ItemName_TXT.Text = rate;
}
same for another form but i no want to close my main form1 and only close other forms while clicking button constructor called but fields not populated why
NOTE:
I HAVE TO FILL TEXTBOXES OF ALREADY OPENED FORM FORM1
from another form get object of opened form
Form1 f = (Application.OpenForms[0] as Form1);
f.PName_TXT.Text = name.ToString();
f.PId_LBL.Text = id.ToString();
}
If Form1 is already open, it means the constructor had already run. Make a setter method and call the method from other form.
public void UpdateUnitAndRate(string units, string rate)
{
ItemId_LBL.Text = units;
ItemName_TXT.Text = rate;
}
//put it in form2 (or itemform) as a field
Form1 f1;
//add this in the method or event (in itemform) you want to update units and rates in form1
if (f1 != null)
f1.UpdateUnitAndRate(units, rate);
else
f1 = new Form1(units, rate);
I think what you are looking for is Application.OpenForms, use this to create an instance of the open form and access the textbox.

passing variables form to form private to global in c#?

Been working on a simple c# windows app program. I have been able to pass a few variables from one form to the next and use them using form2 y = new form2(passingVariable); y.ShowDialog(); and then on the next form public form2(string myVariable). However this method only allows me to use the variable within those curly braces. Currently I am trying to pass it to the next form in line. However it won't let me use the variable when I try to pass it into the next form using the code line I provided above. It gives me the error The name 'userName' does not exist in the current context I have a lot of source code and didn't know what exactly was needed for me to share so here is the link to my webng.com account with a very simple web page set up with my source code if anyone needs to review it.
Try creating another variable on that current form to store that Username and then assign the username passed into that variable. Your constructor will be like this then:
private string username;
public talkingWithProgram(string userName, string pcName)
{
InitializeComponent();
this.Text = pcName;
programQuestion.Text = "Whatcha wanna talk about \n" + userName + "?";
this.userName = userName;
}
sportsCategories y = new sportsCategories(userName);
Creating a new sportsCategories class now passes userName from this context, which has the value from the previous form. Currently it looks like you're referring to the userName in the constructor which is in the method context and out of scope outside.
I would avoid setting specific variables in the constructor of a windows form. In general, it is more customary to use getters and setters, or a function designated specifically for this purpose.
For example: If you can have the code form2 y = new form2(passingVariable); instead you can have the code
form2 y = new form2();
form2.SetMyVar(passingVariable);
OR, if you are using getters and setters:
form2 y = new form2();
form2.SetMyVar = passingVariable
That way, whenever you need to set or update the variable you can do it as long as you have a reference to the form. Also, in said SetMyVar() function (if you choose that method), be sure to set a class variable. In your code, class variables go outside your functions, so that they are visible to all functions of that instance of the class.
initialize a variable in a class xyz
assign the values to them in constructor like
String a1,b1=String.empty
Class xyz
{
xyz(string a,string b)
{ //constructor
a1=a;
b1=b;
//Now use them in whole class
}
}
or if you want to use them in whole application then initialize them globally in Program.cs
then you can set and get values like
Program.a1="abc" //assigning value

Method return value resets value after changing into another form

I have a form, Form2 which contains a Hangman game (yes, it is the similar Hangman game to the one that i'm referring to in my previous question) and once the player finishes the game, the player will be brought to either one of two forms, Form4 and Form6 (one is a congratulations form for winning and one is a mocking/defeat form for losing) and in both forms Form4 and Form6, there is a label that displays the score that the player gets from the previous Form2.
I had placed a method to return the value of the score in Form2.
public int getScore()
{
return score;
}
And then in both forms, Form4 and Form6, there is these codes in each form respectively.
Form4
private void Form4_Load(object sender, EventArgs e)
{
Form2 game = new Form2();
lblFinalScore.Text += game.getScore().ToString();
}
Form6
private void Form6_Load(object sender, EventArgs e)
{
Form2 game = new Form2();
lblFinalScore.Text += game.getScore().ToString();
}
So after passing Form2 and playing the game, and when for example, I won the game and got 7 points, and Form4 appears, the lblFinalScore displays 0... WHY?!
Please help...
If you use the new keyword you create a new instance of the Form2 class.
This way you are using two different instances. Differnt instances are having data fields with different values.
If you want to access the same data field from any intances of a class, use the static keyword. You could store the score value in a static field, this way you could easily access it.
If you have a static field defined in a class, you can access the very field from any instance. However, using static fields are highly discouraged, since this violates basic OO principles.
Example:
class Program
{
static void Main(string[] args)
{
ExampleClass ex1 = new ExampleClass();
ExampleClass ex2 = new ExampleClass();
ex1.normalfield = "new value for ex1";
ex2.normalfield = "new value for ex2";
ExampleClass.staticfield = "static value";
Console.WriteLine(ex1.normalfield);
Console.WriteLine(ex2.normalfield);
Console.WriteLine(ExampleClass.staticfield);
}
class ExampleClass
{
public string normalfield = "";
public static string staticfield = "";
}
}
Passing the original instance of the Form could be a better way to go in your situation.
This could be done by storing a reference to the Form, or implementing the Singleton pattern.
However, the best solution in my opinion, would be to decouple the presentation of your game logic. You should be using a different class to implement the game logic and to store data values connected to the game and the form classes should be only responsible to present visually the current state of the object representing the state of your game.
You are creating two different instances of Form2. Refer to actual original instance of Form2.
Have class level variable on both Form4 and Form6 and set it from respective constructor. Pass instance from Form2.
Refer to Passing a value from one form to another.

Accessing string from another Form

Hello I have datagridview in form1 and through form1 I open form2 and through form2 I open form3 and string named vyber_ID_K placed in Form1 needs to be accessed in Form3 (I need to get its value in Form3)
this is placed on button click in form1
form2 a = new form2 ("Novy");
string vyber_IDK = (string)dataGridView1.CurrentRow.Cells["ID_K"].Value.ToString();
a.vyber_ID_K = vyber_IDK;
a.Show();
a.Closed += klient_Closed;
I would like to access vyber_ID_K in form 3, how it can be done? I tried to set public string vyber_ID_K in form2 and pass it similary to form3 but I get null. Am I doing it right? Is there any other better solution please?
Thanks in advance.
My step-by-step according to Servy:
button click in Form 1
Func vyberIDKGetter = () => dataGridView1.CurrentRow.Cells["ID_K"].Value.ToString();
try
{
form2 = new form2 ("Novy");
a.vyberIDKGetter = () => dataGridView1.CurrentRow.Cells["ID_K"].Value.ToString();
a.Show();
}
button click in form2
public Func vyberIDKGetter;
private void button1_Click(object sender, EventArgs e)
{
nova_platba b = new nova_platba("novy");
b.vyberIDKGetter();
b.Show();
b.Closed += klient_Closed;
}
In form3
Func<string> vyberIDKGetter = veberIDK;
string vyberIDK = vyberIDKGetter();
SqlCommand sc = new SqlCommand(#"
INSERT INTO kliplat (datum,text,castka,akce,subkey,priznak,rocnik)
VALUES (#datum,#text,#castka,#akce,#subkey,#priznak,#rocnik);
SELECT scope_identity();
", spojeni);
sc.Parameters.AddWithValue("#subkey", vyberIDK);
So the issue here is that the value that you want doesn't exist yet when you're constructing Form2, or even Form3 for that matter. It needs to have some means of accessing the data at some point in the future. We can get this behavior by leveraging delegates.
Rather than passing a string to Form2, when that form is constructed (since we don't know what the string will be yet) pass a Func<string>. That object will be a method that, when invoked, will provide a string that represents the needed value. Form1 can define it like this:
Func<string> vyberIDKGetter =
() => dataGridView1.CurrentRow.Cells["ID_K"].Value.ToString();
Then in Form3 when it's holding onto the function that was passed it can get the string out by simply invoking that delegate:
Func<string> vyberIDKGetter = [...];
string vyberIDK = vyberIDKGetter();
This approach to solving the problem is particularly adventageous in that Form3 doesn't need to know anything about Form1 or Form2. If there is some other caller that wants to use it they can provide their own delegate instead. If there is a developer handling the coding of each form they don't need to communicate all of the internal details of each form to each other, they can just handle the passing of this delegate and then be able to treat the caller/callee as a black box.
You have to make a public getter/setter around the string:
public string Vyber_ID_K
get
{
return vyber_ID_K;
}
set
{
vyber_ID_K = value
}
That you need a reference from Form 1 in Form 2, and from Form 2 in Form 3. So you can access
each Form.
You can't use a string as Referenced Parameter, becuase it is an immutable class. String C#
That is a really odd that you pass a parameter via the constructor
form2 a = new form2 ("Novy");
and in the same time you pass another parameter via the property
a.vyber_ID_K = vyber_IDK;
Why don't you instead pass all parameters via the constructor?
string vyber_IDK = (string)dataGridView1.CurrentRow.Cells["ID_K"].Value.ToString();
form2 a = new form2 ("Novy", vyber_IDK);
and in Form2
public class form2
{
private string Name { get; set; }
private int vyber_IDK { get; set; }
public form2( string Name, int vyber )
{
this.Name = Name;
this.vyber_IDK = vyber_IDK;
}
Then, passing anything to form3 from form2 works in the same way
form3 f = new form3( this.vyber_IDK );

Categories

Resources