so I'm trying to make a simple pop-up box in which you can insert multiple different inputs
(first name, last name, etc...) info and it will be saved as a string. I tried using built-in text boxes but was unable to understand how it really works. Is there an easier way of doing so?
I'm using win forms if that's relevant.
It does not make sense to simply return a string, instead consider creating a class to represent your data and override ToString as per below to have the option to have a string representation of the data or to have properties for each element to collect.
You need to create a form (in this case UserInputForm), place labels and controls on the form to collect input. Validation may be done in this form or by the calling form.
Simple example, we want first, last name and birth date, add text boxes for first and last name and a DateTimePicker for birth date. A submit/ok button and a cancel button. For the Cancel button set DialogResult to Cancel in the property window.
Create a class to represent the data to be collected e.g.
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
}
In the form to collect data. Note form level variable for returning data of type Person which the calling form uses if the sumbit button is pressed.
public partial class UserInputForm : Form
{
public readonly Person Person = new Person();
public UserInputForm()
{
InitializeComponent();
}
private void SubmitButton_Click(object sender, EventArgs e)
{
Person.FirstName = FirstNameTextBox.Text;
Person.LastName = LastNameTextBox.Text;
Person.BirthDate = BirthDateTimePicker.Value;
DialogResult = DialogResult.OK;
}
}
In the form to call the above form
private void GetPersonDetailsButton_Click(object sender, EventArgs e)
{
UserInputForm f = new UserInputForm();
try
{
if (f.ShowDialog() == DialogResult.OK)
{
MessageBox.Show($"{f.Person.FirstName} {f.Person.LastName} {f.Person.BirthDate:d}");
}
else
{
MessageBox.Show("Cancelled");
}
}
finally
{
f.Dispose();
}
}
Then there is validation which can be done in the submit button event or in the calling form.
Simple example for in form validation.
private void SubmitButton_Click(object sender, EventArgs e)
{
if (!string.IsNullOrWhiteSpace(FirstNameTextBox.Text) & !string.IsNullOrWhiteSpace(LastNameTextBox.Text) & BirthDateTimePicker.Value < DateTime.Now)
{
Person.FirstName = FirstNameTextBox.Text;
Person.LastName = LastNameTextBox.Text;
Person.BirthDate = BirthDateTimePicker.Value;
DialogResult = DialogResult.OK;
}
else
{
// present user with a dialog to correct input
}
}
And if you really want a string alter the last to override ToString
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
public override string ToString() => $"{FirstName},{LastName},{BirthDate:d}";
}
Usage
if (f.ShowDialog() == DialogResult.OK)
{
MessageBox.Show(f.Person.ToString());
}
else
{
MessageBox.Show("Cancelled");
}
Full source
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
enter image description hereI have used AutoSize/FixedDialog/GrowAndShrink combo before to set Formsize depending on the label size responsible for printing the Queryresult out. In this case I have done everything in the same way but the Shrink part is not functioning at all.
The label is also set AutoSize. Maximum size is determined, to have only the height autosized.
I have checked ten times all of the properties human can set and the difference between the former Forms and the one I have problem with. The conclusion:No difference (Instead of two little things (margin size and minimum size)).
I use property window when is it possible, so I can not present any code to this question.
I would like to now what is wrong in my thinking or what shoud I do more. It is a good answer for me that: Forget about the property window! Code! You want to be a developer.
public partial class Form1 : Form
{
public class QuerySelection
{
public string Name { get; set; }
public string Query { get; set; }
public QuerySelection(string name, string query)
{
Name = name;
Query = query;
}
public override string ToString()
{
return Name;
}
}
public Form1()
{
InitializeComponent();
}
private void buttonCancel_Click(object sender, EventArgs e)
{
this.Close();
}
const string QueryText1 = "This is the short selection!";
const string QueryText2 = "This is the middle-long selection!";
const string QueryText3 = "This is the long selection!";
const string Query1 = "short";
const string Query2 = "middle-short";
const string Query3 = "long";
const string ErrorText = "Choose a query!";
private void Form1_Load(object sender, EventArgs e)
{
comboBoxQueries.Items.Add(new QuerySelection(QueryText1, Query1));
comboBoxQueries.Items.Add(new QuerySelection(QueryText2, Query2));
comboBoxQueries.Items.Add(new QuerySelection(QueryText3, Query3));
}
private void buttonSelectedQueryResult_Click(object sender, EventArgs e)
{
QuerySelection selectedItem = (QuerySelection)comboBoxQueries.SelectedItem;
if(comboBoxQueries.SelectedItem == null)
{
MessageBox.Show(ErrorText);
}
else
{
labelResult.Text = selectedItem.Query;
}
}
}
}
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.
I have created a simple form "people" and there is another file "Information.cs"
In main for assign text box "txt_lname" value to a variable
String lastname = txt_lname.Text;
Then I want to use this value within "information class" (It is a thread class)
How can I use it ?
(I have commented the place I wanted to use that value)
Main Form
namespace users
{
public partial class people : Form
{
public people()
{
InitializeComponent();
}
private void btn_login_Click(object sender, EventArgs e)
{
String lastname = txt_lname.Text;
}
}
}
Information Class
namespace users
{
class Information
{
int[] idno = new int[10];
int[] age = new int[10];
string[] fname = new string[10];
// Here I want to assign txt_lname.Text value to a variable
lastname = txt_lname.Text; // This code is not working
public void run()
{
while (true)
{
for (int i = 0; i < 600; i++)
{
//Some code here
try
{
Thread.Sleep(100);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OKCancel, MessageBoxIcon.Error);
}
}
}
}
}
}
* Can I use value of a variable within run method in thread class ? if cannot then why ?
You have to create an instance of Information on your form and then pass the data to said instance. A classes' code won't magically be executed just because you added it to your project, you have to actually create an instance of the class.
So lets create and initialize an instance of Information on the form:
public partial class people : Form
{
private Information _information;
public people() {
InitializeComponent();
_information = new Information();
}
}
You can now pass stuff to your instance of Information. But to do that you need a way to pass it, or in this case Information needs a way to receive a LastName. There's more than one way to do this but a common approach is to expose a LastName property on Information:
public class Information
{
...
public string LastName { get; set; }
...
}
And now you can pass the value to the LastName property:
private void btn_login_Click(object sender, EventArgs e) {
_information.LastName = txt_lname.Text;
}
Note: When you want to execute the run method on Information you'll do it through the instance just like when you're setting the LastName:
private void btn_run_click(object sender, EventArgs e) {
_information.run();
}
Make the Information class Static
public static class Information
And in your main form you can use it like
Information.LastName = txt_lname.Text;
But you also need to declare LastName as property. So add
public string LastName {get; set;}
into your Information Class.
I'm having trouble getting the value of a textbox of a popped up dialog. I've followed the advice from other StackOverflow questions that said to create a public variable in program.cs:
public static string cashTendered { get; set; }
Then I created my dialog like this:
Cash cashform = new Cash();
cashform.ShowDialog();
And when the user presses the button on the dialog, this is called:
if (isNumeric(textBox1.Text, System.Globalization.NumberStyles.Float))
{
Program.cashTendered = textBox1.Text;
this.Close();
}
else
{
MessageBox.Show("Please enter a valid amount of cash tendered. E.g. '5.50'");
}
Yet Program.cashTendered stays null. Am I doing something wrong? Thanks!
For starters your form called Cash should use an object oriented design. It should have a public property called CashEntered or something similar of type decimal instead of string. You would call the Form like so:
using (var cashDialog = new CashDialog())
{
// pass a reference to the Form or a control in the Form which "owns" this dialog for proper modal display.
if (cashDialog.ShowDialog(this) == DialogResult.OK)
{
ProcessTender(cashDialog.CashEntered);
}
else
{
// user cancelled the process, you probably don't need to do anything here
}
}
Using a static variable to hold the results of a temporary dialog is a bad practice. Here is the better implementation of a dialog:
public class CashDialog : Form
{
public decimal CashEntered { get; private set; }
private void ok_btn_Clicked
{
decimal value;
if (Decimal.TryParse(cashEntered_txt.Text, out value))
{
// add business logic here if you want to validate that the number is nonzero, positive, rounded to the nearest penny, etc.
CashEntered = value;
DialogResult = DialogResult.OK;
}
else
{
MessageBox.Show("Please enter a valid amount of cash tendered. E.g. '5.50'");
}
}
}
On your main form that you want to get the value for, you'd have some sort of code like this;
var cashTendered;
using (var frm = new Cash())
{
if (frm.ShowDialog() == DialogResult.OK)
cashTendered = frm.GetText()
}
Then on your dialog form, you'd have something like this:
public string GetText()
{
return textBox1.Text;
}
public void btnClose_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.OK;
this.Close();
}
public void btnCancel_Click(object sender, EventArgs e)
{
this.Close();
}
Alternatively, you can just perform those lines in the btnClose_Click event in the FormClosing event instead if you don't have a button for them to click to 'submit' their value.
Edit You might want to add some sort of validation on your textbox inside the btnClose event, such as:
decimal myDecimal;
if (decimal.TryParse(textBox1.Text, out myDecimal))
{
this.DialogResult = DialogResult.OK;
this.Close();
}
else
{
MessageBox.Show("Invalid entry", "Error");
textBox1.SelectAll();
}