I need to make windows forms program, that:
a) shows 2 forms with one textbox and one button each
b) when you press the button on one form, program copies text from that form to second form
c) when you press the button on the second form, program copies text from that form to first form
I've tried several different aproaches and got bogged down in encapsulation problems, since both forms has to be in separate instances, right? I've managed to make it work, so it creates new instance of form with new text in textbox every time you click, but after several steps I ended up with screen full of new windows and I need it to show only 2 windows through whole runtime.
Create the windows in your Main method, but don't show them immediately, then access them through the static properties:
public static class Program {
public static Form1 Form1 { get; private set; }
public static Form2 Form2 { get; private set; }
public static Int32 Main(String[] args) {
using( Program.Form1 = new Form1() )
using( Program.Form2 = new Form2() ) {
Application.Run( Program.Form1 ); // Form1's `Load` method would then show `Form2`
}
Program.Form1 = Program.Form2 = null;
return 0;
}
}
Form1 (is responsible for showing Form2 because Application.Run only shows a single form itself):
public class Form1 : Form {
protected override void OnLoad(...) {
Program.Form2.Show();
}
private void Button1_Click(...) {
Program.Form2.TextBox1.Text = this.textBox1.Text;
}
}
Form2 (you need to expose its TextBox via a public property):
public class Form2 : Form {
public TextBox TextBox1 { get { return this.textBox1; } }
}
Here's an example that shows how to pass a reference to the first form, into the second form using its Constructor. That reference is stored at class level so it can be used later. The exact same code/form is being used for both instances:
public partial class Form1 : Form
{
private Form1 target = null;
public Form1()
{
InitializeComponent();
this.Text = "Instance #1";
this.target = new Form1(this);
this.target.Text = "Instance #2";
this.target.Show();
}
public Form1(Form1 target)
{
InitializeComponent();
this.target = target;
}
private void button1_Click(object sender, EventArgs e)
{
if (this.target == null || this.target.IsDisposed)
{
this.target = new Form1(this);
this.target.Show();
}
this.target.textBox1.Text = this.textBox1.Text;
}
}
got bogged down in encapsulation problems, since both forms has to be in separate instances, right?
"encapsulation" immediately made me think of nested classes. The quintessential use case is for a class that is not/should not be used anywhere except in the containing class.
The idea is to allow clients to instantiate Form1 but have no access to Form2 or any of its members. If you need to expose anything from Form2 I suggest you write Form1 properties so that the client sees everything coming from Form1 only.
public class Form1 : Form {
protected Form Sibling { get; set; }
public Form1() {
Sibling = new Form2(this);
}
protected override void OnLoad(...) {
Sibling.Show();
}
private void Button1_Click(...) {
Sibling.TextBox1.Text = this.textBox1.Text;
}
protected class Form2 : Form {
protected Form Sibling { get; set; }
public Form1 ( Form mySibling ) {
Sibling = mySibling;
}
private void Button1_Click(...) {
Sibling.TextBox1.Text = this.textBox1.Text;
}
} // Form2
} // Form1
Related
i have 2 forms that consist of around 20 TextBoxes and i want to save all 20 entries and show them all in the 3rd form, each being shown in different labels, i have saved all 20 data in individual public static stringglobal variables, but having 20 static global variable takes a lot of memory and slows down the program, is there any other way to save these data and store them individually in labels ?
here is what i have tried:
first form:
public static string place_of_application;
public static string gender;
private void bunifuFlatButton1_Click(object sender, EventArgs e)
{
place_of_application = PlaceOfApplication.Text;
gender = identity.Text;
...
}
second form:
private void PrintTemplateForm_Load(object sender, EventArgs e)
{
label36.Text = userform2.place_of_birth;
label34.Text = userform2.gender;
...
}
thanks for the help
Let's say you have two forms, the main form and the secondary form. You have bunch of text boxes in main, and upon clicking a button you want to grab data from those and show them in form 2.
First I would define a class that represents data you want to send/receive. It seems to be some sort of personal data, so let's create a Person class:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
Obviously, you will have all your 20 things you want as properties in the class instead of just this two.
Now the idea is grab data from your text boxes and save in an instance of this object. Next, In the second form you want to launch, let's pass a Person object in the constructor. So the second form's code behind will look like this. We will save that Person information in form two, and then display on it's labels.
public partial class SecondForm : Form
{
public Person Person { get; set; }
public SecondForm(Person person)
{
InitializeComponent();
Person = person;
}
private void SecondForm_Load(object sender, EventArgs e)
{
lblName.Text = Person.Name;
lblAge.Text = Person.Age.ToString();
}
}
Now in main form, when a button is clicked, we'll save the data to an instance of the Person class, then pass it into the constructor of SecondForm and then show it.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var person = new Person();
person.Name = txtName.Text;
if (int.TryParse(txtAge.Text, out int age))
{
person.Age = age;
}
var form2 = new SecondForm(person);
form2.Show();
}
}
One approach could be to select all of your textboxes in your first form and in Properties windows of Visual Studio (i'm guessing you use this IDE) go to Modifiers property and select Public from the list,
Or you can directly edit Form1.Designer.cs file and change all of the textboxes you want from Private to Public, then you can access them directly from your 2nd form like this:
Form1 frm = new Form1();
frm.ShowDialog();
if (frm.DialogResult == DialogResult.OK)
label1.Text = frm.textBox1.Text;
I think you have the XY problem. You are asking for a very specific problem, when your issue is far more general with the architecture of the application.
Recommendation
Try to take advantage of the object oriented features of C# and build a data model (i.e. a class that contains all the data). Then you can pass around this class (or actually a reference to the class) from one form to the other. Each form will be responsible for populating their own text boxes from the data model, or generating a new instance of the data model from the text boxes.
As an added bonus, to this setup is that you can use data binding to automate the synchronization between your data model and the UI (i.e. the text boxes).
I strongly recommend reading a book on windows programming, or find online resources with examples. [SO] is not a good place to learn how to build windows applications properly.
Example
Data model is a class that holds data
public class PersonalInformation
{
public string PlaceOfApplication { get; set; }
public string Gender { get; set; }
// .. more here
}
Main form can receive or send data via a PersonalInformation object.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public PersonalInformation PersonalInformation
{
get
{
return new PersonalInformation()
{
PlaceOfApplication = placeOfApplicationTextBox.Text,
Gender = genderTextBox.Text
};
}
set
{
placeOfApplicationTextBox.Text = value.PlaceOfApplication;
genderTextBox.Text = value.Gender;
}
}
}
In the second form create a method to receive data
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
public void SetPersonalInformation(PersonalInformation value)
{
placeOfApplictionLabel.Text = value.PlaceOfApplication;
genderLabel.Text = value.Gender;
}
}
In the first form handle the button press by preparing and sending the information to the second form
public partial class Form1 : Form
{
...
private void secondFormButton_Click(object sender, EventArgs e)
{
var dlg = new Form2();
dlg.SetPersonalInformation(this.PersonalInformation);
if (dlg.ShowDialog(this) == DialogResult.OK)
{
// user pressed OK in second form
}
}
}
Test the process
Inside my public partial class frmMain : Form I have private class Tile.
Inside the class Tile I have private PictureBox pic = new PictureBox();.
I have registered a click event for those pictureBoxes (inside the Tile class):
public void Initialize()
{
pic.Click += new EventHandler(swap);
}
When I click a pictureBox I want to be able to see textbox1.Text.
private void swap(object sender, EventArgs e)
{
// code here //
if (won)
{
MessageBox.Show(textBox1.Text);
}
}
How can I make textbox1.Text and some other fields of my frmMain instance visible?
The quickest solution would be to pass frmMain as parameter to Tile class. Tile class would be:
private class Tile {
private frmMain frm;
//constructor
public Tile(frmMain frm) {
this.frm = frm;
}
... your code ...
//now you can
private void swap(object sender, EventArgs e)
{
if (won)
{
MessageBox.Show(frm.textBox1.Text);
}
}
}
Remember that the textBox1 have to be public accessible from frmMain.
The cleanest solution would be to expose interface from frmMain and pass it as parameter to Tile class.
Interface
public interface IfrmMain_GetText
{
string gettextBox1Text();
}
frmMain
public partial class frmMain : Form, IfrmMain_GetText
{
... your code ...
public string gettextBox1Text(){
return textBox1.Text;
}
}
Tile class
private class Tile {
private IfrmMain_GetText frmInterface;
//constructor
public Tile(IfrmMain_GetText frmInterface) {
this.frmInterface = frmInterface;
}
... your code ...
//now you can
private void swap(object sender, EventArgs e)
{
if (won)
{
MessageBox.Show(frmInterface.gettextBox1Text());
}
}
}
How can I make textbox1.Text and some other fields of my frmMain instance visible?
In C# windows forms, controls are private by default. To change the access modifier, you can change it like below:
Right click the control > Properties > Change dropdown as shown below
I would change it to internal, no need to make it public in your case.
That means classes outside the class where the control is (frmMain) can access the control. But your inner class will need a reference to frmMain so it can access the controls of frmMain. To do that, you can do it in the following ways:
Option 1
You can pass the frmMain reference to a class in the constructor:
public class SomeClass
{
private frmMain someForm;
public SomeClass(frmMain someForm)
{
this.frmMain = someForm;
// Now you can do this
var ctrl = this.frmMain.WhateverControlYouNeedToAccess;
string controlText = ctrl.Text; //assuming it has Text property
}
}
During creation of the SomeClass, pass your form to it:
// this reference to the current instance
// this code will be in your form
SomeClass some = new SomeClass(this);
Option 2
In your class have a property so it is settable from outside like this:
public class SomeClass
{
public frmMain SomeForm { get; set; }
}
You will set the property like this:
SomeClass some = new SomeClass();
some.SomeForm = this;
Option 3
Only give the class the minimum it needs. You do not need to give it a reference to the whole form but only one control (or more), then pass the control specifically like this:
SomeClass some = new SomeClass();
some.PictureBoxA = this.pictureBox1;
some.Button1 = this.button1;
For this to work, your class needs to have the properties for the above. So your class will have properties like this:
public class SomeClass
{
public PictureBox PictureBoxA { get; set; }
public Button Button1 { get; set; }
}
You need to pass a form-reference to the nested class. You can do so through constructor.
private class Tile
{
private frmMain _frm;
public Tile (frmMain frm)
{
_frm = frm;
}
private void swap(object sender, EventArgs e)
{
if (won) {
MessageBox.Show(_frm.textBox1.Text);
}
}
}
You either need to make textBox1 public or to encapsulate it in a public property.
A cleaner way is to hold the information in a data class and to use object binding to bind its properties to the textboxes. Then you can pass this data object to the Tile class.
See: A Detailed Data Binding Tutorial on CodeProject.
I don't know what kind of data is displayed on your form, but if tile data is displayed, then the Tile class could act as data class and you could bind the tile object to your form.
My intension is to create a dynamic textbox in Form1. I have a Class 'Form1' and a Class 'SplBox'. I have declared a dynamic textbox in class 'SplBox' & passed a string to it. All I want is to call this dynamic textbox in class 'Form1' & display it in Form1 main form. In my above code a new form is getting opened up & then in this new form the dynamic textbox is shown - which I do not want
namespace TxtClassRun
{
public partial class Form1 : Form
{
SplBox s1 = new SplBox();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// show the dynamic text box in Form1
s1.settxtbox();
s1.Show(); // opening another window. I want it to be in "Form1"
}
}
//New Class
public partial class SplBox : Form
{
//Global declarations
TextBox t2 = new TextBox();
public void settxtbox()
{
t2.Text = "Hello World";
Controls.Add(t2);
}
}
}
Try this,
public partial class SplBox : Form
{
//Global declarations
TextBox t2 = new TextBox();
private Form TempOwnerForm;
public SplBox(Form TempOwnerForm) {
this.TempOwnerForm = TempOwnerForm;
}
public Form OwnerForm { get { return TempOwnerForm; } set { this.TempOwnerForm = value; } }
public void settxtbox()
{
t2.Text = "Hello World";
TempOwnerForm.Controls.Add(t2);
}
}
Hope helps,
I'm trying to get listbox selected item from one form 1 to display on textbox on form 2.
So far it's working partly.
The problem is that it only gets the selectedItem that was selected at the start of the application. If the user selects a new item, it still gets the one that was selected as default.
Form 1 MainForm:
public MainForm()
{
public string GetListBoxSelectedItem()
{
if (Animallst.SelectedItem != null) //Animallst is the listbox
{
return Animallst.SelectedItem.ToString();
return string.Empty;
}
}
private void foodbtn_Click(object sender, EventArgs e)
{
FoodRegister foodForm = new FoodRegister();
foodForm.Show();
}
}
Form 2 FoodRegister:
public partial class FoodRegister : Form
{
private RecipeManager m_foodmanager = new RecipeManager();
public FoodRegister()
{
InitializeComponent();
MainForm main = new MainForm();
Nametxt.Text = main.GetListBoxSelectedItem();
//My initializations
InitializeGUI();
}
}
These two lines are not at all doing what you want them to do. You're creating an entirely new instance of MainForm, which has nothing to do with the original instance. And so GetListBoxSelectedItem() doesn't do what you want either.
MainForm main = new MainForm();
Nametxt.Text = main.GetListBoxSelectedItem();
Instead, pass a reference to the original Form into the second Form:
public FoodRegister(MainForm main)
{
InitializeComponent();
Nametxt.Text = main.GetListBoxSelectedItem();
...
And then call it like this:
FoodRegister foodForm = new FoodRegister(this);
foodForm.Show();
A couple of things to mention:
The line return string.Empty is redundant. Because of the line above it, this line becomes unreachable
In your FoodRegister for, you create a new instance of your main form. This then wipes anything that the main form was holding - i.e. Animallst.SelectedItem.ToString();
An easy way to handle this is to set the value to a static variable - that way you won't have to create a new instance of the form to access it.
Main form:
public static string GetListBoxSelectedItem()
{
if (Animallst.SelectedItem != null) //Animallst is the listbox
{
return Animallst.SelectedItem.ToString();
}
else { return string.Empty(); }
}
Food Register:
public FoodRegister()
{
InitializeComponent();
MainForm.GetListBoxSelectedItem();
//My initializations
InitializeGUI();
}
Haven't played with WinForms in awhile but here goes
In Form 2
public partial class FoodRegister : Form
{
private RecipeManager m_foodmanager = new RecipeManager();
public FoodRegister()
{
InitializeComponent();
//My initializations
InitializeGUI();
}
public void SetText(string txt)
{
Nametxt.Text = txt;
}
}
In Form 1
public MainForm()
{
private readonly FoodRegister foodForm = new FoodRegister();
private void foodbtn_Click(object sender, EventArgs e)
{
foodForm.SetText(Animallst.SelectedItem == null ? "" : Animallst.SelectedItem.ToString());
foodForm.Show();
}
}
I replaced
GetListBoxSelectedItem()
with
Animallst.SelectedItem == null ? "" : Animallst.SelectedItem.ToString()
I have a textbox7 created in form1, but I want to access it in another form, form 2 so I changed its modifiers to public
When I get on form2 i want it to perform the following
Form1.textBox7.ReadOnly = true;
but I get the following error
Error 1 An object reference is required for the non-static field,
method, or property
'WindowsFormsApplication1.Form1.textBox7' C:\Users\Admin\Google
Drive\AdminhomeGD\ztese\zprograma\WindowsFormsApplication1\WindowsFormsApplication1\formOpConfig.cs 73 46 WindowsFormsApplication1
i have no idea what's wrong
Edit:
I'm trying to use the following, on form1 (named Form1):
public Boolean gammamanual
{
get { return textBox7.ReadOnly; }
set { textBox7.ReadOnly = value; }
}
while on form2 (named formOpConfig):
namespace WindowsFormsApplication1
{
public partial class formOpConfig : Form
{
public formOpConfig(Form1 opener)
{
// this is a constructor
this.Opener = opener;
}
private Form1 Opener { get; set; }
public formOpConfig() { // initialization and stuff }
private void buttonExit_Click (object sender, EventArgs e)
{
if (checkBox3.Checked == true) { this.textBox7.gammamanual = false; }
else { this.textBox7.gammamanual = true; }
this.Hide();
}
I want it so that when the checkbox3 is checked and the form2 exited, the textBox7 will be editable manualy.
Edit:2 the problem was that form2 was started from form1, also, i had 2 different constructors in form2 (formOpConfig). the solution was adapting the main constructor using
private Form1 Opener { get; set; }
public formOpConfig(Form1 opener)
{
this.Opener = opener;
InitializeComponent(); //Stuff
}
meanwhile i was able to start formOpConfig from the Form1 using
formOpConfig painelconfig = new formOpConfig(this);
painelconfig.ShowDialog();
You cannot access an instance variable via class name, that works only if it's static. So you need an instance of Form1 to access a property/field of it. You could for example pass it via constructor from Form1 to Form2(if Form1 instantiates Form2) or use a property/method.
But instead of exposing the complete control i would only provide what is necessary, that's called Encapsulation. You could expose a public property with a meaningful name that describes the purpose of textBox7(change also this name). Presuming it's purpose is to show a username the property could be UserName:
public partial class Form1 : Form
{
public string UserName
{
get{return TxtUserName.Text;}
set{ TxtUserName.Text = value;}
}
// ...
}
Since you want to get/set the ReadOnly property of the TextBox you could provide another property:
public bool UserNameEditable
{
get{ return !TxtUserName.ReadOnly; }
set{ TxtUserName.ReadOnly = !value; }
}
Now you are able to get/set it from another Form if you have an instance of Form1:
public partial class Form2 : Form
{
public Form2(Form1 opener)
{
// this is a constructor
this.Opener = opener;
}
private Form1 Opener { get; set; }
private void SomeMethod()
{
this.Opener.UserName = "Tim";
this.Opener.UserNameEditable = false;
}
// ...
}
You need to pass the Form1 instance to the constructor of Form2 when you instantiate it. Another approach is to make the property Opener public and use that which suffers the disadvantage that you cannot be sure that it was set.
Another approach is using LINQ and Application.OpenForms which is elegant but error-prone:
var form1 = Application.OpenForms.OfType<Form1>().FirstOrDefault();
form1.UserName = "Tim";
Side-note: Form1 and Form2 are also crying for more meaningful names.
In a form, the controls are created with a private access modifier (see the designer code).
private System.Windows.Forms.TextBox
Therefore, these controls are not accessible from another form. What you should do is create a public or internal property on your form.
public TextBox TextBox7 { get { return textBox7; } }
Once you created an instance of Form1 in (an instance of) Form2, you can access this property.
Form1 frm = new Form1();
frm.TextBox7.ReadOnly = true;
You need to create form1 instance and make a public property to set the control within form1.
public partial class Form2: Form
{
private Form1 objForm1;
public Form2(Form1 frm)
{
InitializeComponent();
//get other form
this.objForm1= frm;
//call here public property of form1 which set controls properties within form1
this.objForm1.SetReadOnly = true;
}
}
Form1
public partial class Form1 : Form
{
//setter Property
public bool SetReadOnly
{
set{ this.TextBox7.ReadOnly= value;}
get{ return this.TextBox7.ReadOnly;}
}
//Form1 Constructor
public Form1()
{
InitializeComponent();
}
//Form1 Load
private void Form1_Load(object sender, EventArgs e)
{
Form2 frm = new Form2(this);
frm.Show();
}
}