Accessing textbox variables from another class - c#

I have a windows form (c#). In the form, the user inputs some text and it then gets saved to an XML. Each time the solution starts, it reads the XML.
At first, I was just testing so I had a master class. Then I started creating different classes and run into a problem.
I can't access the values from the textboxes of the form from the other classes. There are a few other posts asking the same, but I couldn't manage to solve it.
This is what I have:
namespace Emailing
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
XmlController xc = new XmlController();
xc.readXml(); //reads the xml when starts
}
private void button1_Click(object sender, EventArgs e)
{
XmlController xc2 = new XmlController();
xc2.updateXml(); //updates the xmls when the users clicks a button
}
}
}
namespace Emailing
{
class XmlController
{
public void updateXml()
{
DataSet ds = new DataSet();
DataTable dt = new DataTable();
dt.TableName = "Server";
dt.Columns.Add("Server");
ds.Tables.Add(dt);
DataRow row = ds.Tables["Server"].NewRow();
row["Server"] = Form1.textBox6.Text;
ds.Tables["Server"].Rows.Add(row);
ds.WriteXml("Emailer.xml");
}
public void readXml()
{
DataSet ds = new DataSet();
ds.ReadXml("Emailer.xml");
Form1.textBox6.Text = ds.Tables["Server"].Rows[0][0].ToString();
}
}
}
I tried several things with no success.
From what I read, the "best" practice would be to create an interface. I tried but couldn't make it work.
I also tried creating a get set method for the textBox but couldn't make it work. I'm not sure where it should go.
Thanks for your time,

You have instantiated the XmlController class 2 times.
this means that you have 2 objects of the same class, but it are different objects.
what you should do is instantiate the class once and use this object also for the button_Click event (see code)
namespace Emailing
{
public partial class Form1 : Form
{
private XmlController xc;
public Form1()
{
InitializeComponent();
xc = new XmlController();
xc.readXml(); //reads the xml when starts
}
private void button1_Click(object sender, EventArgs e)
{
xc.updateXml(); //updates the xmls when the users clicks a button
}
}
}
however I do suggest you start experimenting with the MVVM pattern see: https://www.codeproject.com/Articles/165368/WPF-MVVM-Quick-Start-Tutorial

If you want to access something from "outside" of a class (the form is a class),
you need it to be Public.
Edit:
namespace Emailing
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
...
}
public string TextOfTextBox1 { get { return Textbox1.Text; } }
}
}
If you have, lets say a 'LoginForm',
You might want to add a property to fetch the given Username as public string UserName { get { return userNameTextBox.Text; } }
(same for the Password, Remmember me, Etc...)

Related

how can I move listbox items to datagridview rows from form2 to form1

Hi I want to move listbox items to datagridview but I'm getting error can you see where I'm going wrong?
I got 2 form,1 datagridview,2 button ,1 listbox and 1 class ( For moving )
form1, got 2 items ( datagridview and 1 button( to open form 2 ))
form2, got 2 item ( listbox and 1 button( to move items datagridview rows )) I think I've created in your mind what I want to do so far, let me add pictures about application too
Picture 1 ( Form1 )
Picture 2 ( Form2 )
In class I added the functions for the buttons ( Shows in picture2 ( Button Load (Is ok) |Button Clear (Is ok) |Button Import (where I'm getting error))
well I have one solution for Import button (Below are the form 1 codes you can check)
public static Form1 instance;
public DataGridView dgv1;
public Form1()
{
InitializeComponent();
instance = this;
dgv1 = dataGridView1;
}
Below are the codes of form2 for the solution
private void btnImport_Click_1(object sender, EventArgs e)
{
foreach (var item in listBox1.Items)
{
int Import = Form1.instance.dgv1.Rows.Add();
Form1.instance.dgv1.Rows[Import].Cells["Email"].Value = item;
this.Close();
}
}
These codes solve my current problem, but it's very confusing when I want to do it for more than one object, so I want to call my operations by creating a method in class, but I get an error doing so
let me share codes for class
using System.Windows.Forms;
namespace Sndr01
{
internal class Class1
{
public string import (ListBox lst , DataGridView dgv)
{
childListForm frm = new childListForm();
string done = lst.ToString();
foreach (var item in lst.Items)
{
int imp = dgv.Rows.Add();
dgv.Rows[imp].Cells["Email Address"].Value = item.ToString();
frm.Close();
}
return done;
}
here is the my form1 codes
public partial class ListForm : Form
{
public DataGridView dgvv;
public ListForm()
{
InitializeComponent();
DataGridViewSettings(dgv1);
dgv1.DataSource = dgvv;
}
}
here is the my form2 codes
public partial class childListForm : Form
{
ListForm lf = new ListForm();
DataGridView dgvx;
public childListForm()
{
InitializeComponent();
dgvx.DataSource = lf.dgvv.DataSource;
}
private void kryptonbtnImport_Click(object sender, EventArgs e)
{
Class1 c1 = new Class1();
c1.import(lstLeadsbox,dgvx);
}
}
where I'm doing wrong? I'm so confused I would be very grateful if you could help
I may have told you a little too much and bored you, but I wanted to specify the details and not leave any question marks in your mind
Thanks
Rather than passing controls between forms a better way is to have an event to pass data from child to parent form.
In this generic example the ListBox is populated with month names. An event is used to pass data to the parent form where the parent form subscribes to the child form event.
Child form code
public partial class ChildForm : Form
{
public delegate void OnPassMonths(string text);
public event OnPassMonths PassMonths;
public ChildForm()
{
InitializeComponent();
listBox1.DataSource = System.Globalization
.DateTimeFormatInfo.CurrentInfo
.MonthNames.Take(12)
.ToList();
}
private void PassDataButton_Click(object sender, EventArgs e)
{
foreach (var monthName in (List<string>)listBox1.DataSource)
{
PassMonths?.Invoke(monthName);
}
}
}
In the main form, month names are added only if non-existing using the following extension method to keep code in the form clean and easy to read.
public static class DataGridViewExtensions
{
// in this case the cell is assumed to be 0, change if not 0
public static bool MonthNotExists(this DataGridView dgv, string month) =>
dgv.Rows.Cast<DataGridViewRow>()
.FirstOrDefault(row => row.Cells[0].Value.ToString()
.Equals(month)) == null;
}
Main form code
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void ShowChildForm_Click(object sender, EventArgs e)
{
ChildForm childForm = new ChildForm();
childForm.PassMonths += OnPassMonths;
try
{
childForm.ShowDialog();
}
finally
{
childForm.Dispose();
}
}
private void OnPassMonths(string month)
{
if (dataGridView1.MonthNotExists(month))
{
dataGridView1.Rows.Add(month);
}
}
}

why I can't get txtBox2.Text and txtBox3.Text value?

public partial class UserControl1 : UserControl,IRequireGraphicInterface
{
private void button1_Click(object sender, RoutedEventArgs e)
{
// int i;
Opcconnect OC = new Opcconnect();
OC.DataRead();
txtBox4.Text = "zjy";
}
}
public partial class Opcconnect : OPCServerClass
{
public void DataRead()
{
UserControl1 TxtgetData = new UserControl1();
try
{
TxtgetData.txtBox2.Text = "SJZ";
TxtgetData.txtBox3.Text ="TEST"
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
}
//I'm beginner, I have tested my program and show noting. I hope get your help how could I get the txtBox2.Text and txtBox3.Text value. thanks.
You've created an instance of UserControl1, but you haven't done anything with that instance. It's not part of any form, it's not displayed to the user, etc. You are successfully setting the values, but never showing those values to the user. Because that instance has nothing to do with any other instance, such as the one you're currently seeing on your screen.
Take a step back. Your Opcconnect class should not be trying to directly set UI controls anyway. It should simply return the data needed by the UI, and the form code should update the controls. For example:
public partial class Opcconnect : OPCServerClass
{
public Tuple<string, string> DataRead()
{
return new Tuple<string, string>("SJZ", "TEST");
}
}
(I've used a Tuple<T1,T2> here because without any context there's no way to know what data structure would be better appropriate. It's likely you'd want a custom class for this. But for now this will at least return two string values.)
Then in your form code you'd get those values and update your controls:
public partial class UserControl1 : UserControl,IRequireGraphicInterface
{
private void button1_Click(object sender, RoutedEventArgs e)
{
Opcconnect OC = new Opcconnect();
var values = OC.DataRead();
txtBox2.Text = values.Item1;
txtBox3.Text = values.Item2;
txtBox4.Text = "zjy";
}
}
Basically, keep your UI code in the UI. Different layers of the application (UI, business logic, database and infrastructure dependencies) shouldn't leak their implementations across layer boundaries, they should consume/return just the data being transferred.

getting values from previous forms in c# winforms

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

Label will not show even when told to show

I am making an application that loads a separate form, the user puts in information, and then when done, it will show up on the primary form the application loaded with first.
The issue is that I tried multiple solutions to get this to load in, but it will not load in after the information is put in. I have tried this.Controls.Add(Label); which is what I have seen the most, but it has not worked. Another way I tried was doing Label.Show();, but the same result, with nothing showing. The AddContacts(string Name) method below is how I add the contact
The AddContact_Click(object sender, EventArgs e) method is a button that, when pressed, opens another form that allows information to be inserted.
public partial class Phonebook : Form
{
public Phonebook()
{
InitializeComponent();
MaximumSize = new Size(633, 306);
}
private void AddContact_Click(object sender, EventArgs e)
{
MakeContact MC = new MakeContact();
MC.Show();
}
public void AddContacts(string Name)
{
Label name = new Label();
//Added Style and Location of Label...
name.Text = Name;
name.Location = new Point(98, 13);
name.Font = new Font("Microsoft Sans Serif", 13, FontStyle.Bold);
this.Controls.Add(name);
Refresh();
}
}
Below is the Method I used when the Finish button is pressed, for when the user is done with the information, and then the AddContacts() method is called
public partial class MakeContact : Form
{
public MakeContact()
{
InitializeComponent();
MaximumSize = new Size(394, 377);
}
private void FinishContact_Click(object sender, EventArgs e)
{
//FullName is the name of the TextField when asking for a name
string Name = FullName.Text;
Phonebook PB = new Phonebook();
PB.AddContacts(Name);
//Closes Separate Form and goes back to the
Close();
}
}
Expectation:
It should load the label into the form after the information is put in.
Actual:
It will not show what so ever.
EDIT: Added More to the Code and to the Question since I didn't do too good of asking the question, sorry about that :/
An example of what I described in the comments:
When you do this:
Phonebook PB = new Phonebook();
you create a new instance of the PhoneBook class (your form): this is not the same Form instance (the same object) that created the MakeContact Form and the one you're trying to update. It's a different object.
Whatever change you make to this new object, it will not be reflected in the original, existing, one.
How to solve:
Add a Constructor to the MakeContact Form that a accepts an argument of type PhoneBook and a private object of type Phonebook:
private PhoneBook pBook = null;
public MakeContact() : this(null) { }
public MakeContact(PhoneBook phoneBook)
{
InitializeComponent();
this.pBook = phoneBook;
}
Assign the argument passed in the constructor to the private field of the same type. This Field will then used to call Public methods of the PhoneBook class (a Form is a class, similar in behaviour to other class).
It's not the only possible method. You can see other examples here.
Full sample code:
public partial class Phonebook : Form
{
private void AddContact_Click(object sender, EventArgs e)
{
MakeContact MC = new MakeContact(this);
MC.Show();
}
public void AddContacts(string Name)
{
Label name = new Label();
// (...)
this.Controls.Add(name);
}
}
public partial class MakeContact : Form
{
private PhoneBook pBook = null;
public MakeContact() : this(null) { }
public MakeContact(PhoneBook phoneBook)
{
InitializeComponent();
this.pBook = phoneBook;
}
private void FinishContact_Click(object sender, EventArgs e)
{
string Name = FullName.Text;
this.pBook?.AddContacts(Name);
this.Close();
}
}

Send text to texbox in another form without making new windows

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

Categories