getting values from previous forms in c# winforms - c#

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

Related

How to retain the value from an numericupdown after closing a form

I have the following question. I am using C# .NET, and I want to save a value in numericupdown box after I close my form. In my aplication I have in total 2 forms, so I want to save the value I enter in the second one, and after I open it again I want to see the last value. In my case the numericupdown value is empty after I open the second form again.
I was thinking about something like this:
namespace Project2
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
decimal a = numericUpDown1.Value;
label2.Text = "N: " + a;
}
}
}
But is still empty after I open it again.
You can create a class which provides set/get for a NumericUpDown control in this case using the following.
public sealed class Setting
{
private static readonly Lazy<Setting> Lazy =
new Lazy<Setting>(() => new Setting());
public static Setting Instance => Lazy.Value;
public decimal NumericUpDownValue { get; set; }
}
In the child form, OnShown set Value property to Settings.NumericUpDownValue then OnClosing remember the value.
public partial class ChildForm : Form
{
public ChildForm()
{
InitializeComponent();
Shown += (sender, args) =>
numericUpDown1.DataBindings.Add("Value", Setting.Instance,
nameof(Setting.NumericUpDownValue));
Closing += (sender, args) =>
Setting.Instance.NumericUpDownValue = numericUpDown1.Value;
}
}
The code above, specifically Settings class is known as the Singleton Pattern which you can learn more about in Implementing the Singleton Pattern in C#.
You can use static variable to store last updated value and with the reference of class name you can use it where ever you want.
From MSDN: Two common uses of static fields are to keep a count of the number of
objects that have been instantiated, or to store a value that must
be shared among all instances.
Like,
namespace Project2
{
public partial class Form2 : Form
{
public static decimal lastNumericUpDownValue = 0;
public Form2()
{
//For example: thiw will print lastest saved Numeric updown value.
//For the first time, it will print 0
Console.WriteLine(Form2.lastNumericUpDownValue);
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//Assign value to lastNumericUpDownValue variable. Look at how it is used.
Form2.lastNumericUpDownValue = numericUpDown1.Value;
}
}
}

Accessing textbox variables from another class

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...)

How can I access a Form's textbox from an instance of a class?

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.

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

Windows Form Application how return value form one form to other

I'm writing an application which will be storing film that i watched and I going to watch in future in XML file ( simple app only for training )
The main object which i use to store data in my app look like :
public class FilmDto : IFilmDto
{
public int FilmId { get; set; }
public string Name { get; set; }
public DateTime? WatchedDate { get; set; }
public int ParentId { get; set; }
public string ParentName { get; set; }
public FilmStatus FilmStatus { get; set; }
public string Category { get; set; }
public string SubCategory { get; set; }
}
All the operation is perform in Service class. There are list of film as main data file.
The service class look this :
public class FilmService
{
private List<FilmDto> _films = new List<FilmDto>();
private FilmDao _filmDao = new FilmDao();
private FilmService()
{
_films = _filmDao.Load();
}
public static FilmService Inicialize()
{
return new FilmService();
}
public void Save()
{
_filmDao.Save(_films);
}
public List<FilmDto> GetFilmsByCriteria(FilmCriteriaDto criteria, bool withStatus)
{
if (withStatus)
{
return _films.Where(x => x.Category.Contains(criteria.Category)
&& x.SubCategory.Contains(criteria.SubCategory)
&& x.ParentName.Contains(criteria.ParentName)
&& x.Name.Contains(criteria.Name)
&& x.FilmStatus.Equals(criteria.FilmStatus)).ToList();
}
else
{
return _films.Where(x => x.Category.Contains(criteria.Category)
&& x.SubCategory.Contains(criteria.SubCategory)
&& x.ParentName.Contains(criteria.ParentName)
&& x.Name.Contains(criteria.Name)).ToList();
}
}
public StatisticDto GetFilmStatistic()
{
return new StatisticDto
{
TotalCount = _films.Count,
TotalToWatch = _films.Where(x => x.FilmStatus == FilmStatus.DoObejzenia).Count(),
TotalWatched = _films.Where(x => x.FilmStatus == FilmStatus.Obejzany).Count()
};
}
public List<string> GetAllParentName()
{
return _films.Select(x => x.ParentName).ToList();
}
public void Add(FilmDto film)
{
_films.add(film);
}
// Private Methods
private int GetNexID()
{
return _films.OrderByDescending(x => x.FilmId).FirstOrDefault().FilmId + 1;
}
}
Now its time to form which i use to resent data. The form use service instance and call method form service to get those data ( form have only display data and do not have any logic to transform it )
public partial class Form1 : Form
{
private FilmService _filmService
public Form1()
{
_filmService = FilmService.Inicialize();
InitializeComponent();
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
FillTable(new FilmCriteriaDto(), false);
}
private void FillTable(FilmCriteriaDto criteria,bool witchStatus)
{
List<FilmDto> films = _filmService.GetFilmsByCriteria(criteria,witchStatus);
foreach (FilmDto film in films)
{
dataGridView1.Rows.Add(film.Name,film.WatchedDate,film.ParentName,film.Category,film.SubCategory,film.FilmStatus);
}
}
private void statisticToolStripMenuItem_Click(object sender, EventArgs e)
{
StatisticDto stats = _filmService.GetFilmStatistic();
MessageBox.Show(string.Format("Total :{0}\nWatched {1}\nTo watch {2}"
, stats.TotalCount, stats.TotalWatched, stats.TotalToWatch), "Stats INFO",MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void addToolStripMenuItem_Click(object sender, EventArgs e)
{
...Call new form to add new film
}
}
To this moment everything is quite nice. But now i need to create new form ( Form2) which will have TexBox to insert new film data to my list in service. No i don't know ho to do this.
First i thought that i change private FilmService _filmService to public FilmService FilmService {get;set;}
And in form2 create constructor where I give Form1 object like public Form2(Form1 form) and make call it form Form1 like : Form2 form = new Form2(this) . In that case i have access to that service method but it will look like form.FilmService.Add which is not nice. In other way i can pass FilmService object as parameter but in that way Form1 will don't know change which Form2 make. I want to create method in Form2 which will be returning FilmDto object to Form1 when e.g i click buton in Form2 is there any way to do that ?
You can use different ways to do this.
The simplest is to use Dialogs. You can open your Form2 as fialog by call ShowDialog and then just read the property if result is OK. It's a general way to implement your behavior in WinForms.
private void addToolStripMenuItem_Click(object sender, EventArgs e)
{
// Show testDialog as a modal dialog and determine if DialogResult = OK.
if (form2.ShowDialog(this) == DialogResult.OK)
{
// Read the contents of testDialog's TextBox.
this.txtResult.Text = form2.TextBox1.Text;
}
}
Note that you must set DialogResult property in Form2 to DialogResult.OK if user click the button and DialogResult.Cancel in other way. It helps you to handle scenario when user has decided not to add new movie.
The other way is to use events. Declare new event in Form2 and subscribe Form1 to this event. Raise new event on button click and pass your data as a parameter of your event.
First of all you can make FilmService static or singleton.
Also you can find some examplex for your particular task here - Communicate between two windows forms in C#
In my Point of View, you should use MVP pattern - https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter
But probably it is overkill.

Categories