I'm new and just started trying out Windows Forms and I've managed to come up the following code for checking for empty textbox:
public partial class form : Form
{
private string results;
}
private void button1_Click(object sender, EventArgs e)
{
results = "";
results += textBox1.Text;
results += textBox2.Text;
...
If (textBox1.Text == "") //I want to take this 'if' statement and turn it into a separate method called checkEmptyFields()
{
MessageBox.Show("This field cannot be left blank.");
textBox1.Focus();
}
else { MessageBox.Show(results, "This is the results window");}
}
Now, my problem comes when I will have 10+ textboxes (such as First Name, Last Name, Address, Email, etc.) that I will need my program to check if their fields have been left empty. How do I take the 'if' statement and make that into another separate method something like checkEmptyFields()?
When I press the button1 to submit the form, that's when I want the checkEmptyFields() to trigger to check for any empty fields in textboxes and display an error message to warn the user.
Related
I'm working on a GUI for an admin interface for management of a student complex. Currently the GUI has a listbox with predefined 6 rules for the students. In the beginning of the code, I add them to a list
private void Form1_Load(object sender, EventArgs e)
{
foreach (string rule in lbRules.Items)
ruleList.Add(rule);
}
Then, the GUI provides the admin with an option to modify the rules. To do so he selects a rule from the listbox and clicks a "Modify" button, which opens another form:
private void BtnModify_Click(object sender, EventArgs e)
{
if (lbRules.SelectedItems.Count > 0)
{
selectedRule = lbRules.SelectedItem.ToString();
selectedIndex = lbRules.SelectedIndex;
selectedRuleNumber = selectedRule.Substring(0, 3);
selectedRule = selectedRule.Substring(6);
var rulesForm = new Rules();
rulesForm.Show();
}
}
On the second form load event I get the rule's text and number:
private void Rules_Load(object sender, EventArgs e)
{
tbRule.Text = Form1.selectedRuleNumber;
tbModifyRule.Text = Form1.selectedRule;
}
The text gets added to a RichTextBox, from where the rule can be edited.
Then the admin clicks a "Save" button, which gets the edited text from the RichTextBox(tbModifyRule) and adds it to a static ruleList in form1, sets a static boolean from form1 to true. Afterwards the second form gets closed:
private void BtnSave_Click(object sender, EventArgs e)
{
saveRule = Form1.selectedRuleNumber + " - " + tbModifyRule.Text;
Form1.ruleList.Insert(Form1.selectedIndex, saveRule);
Form1.ruleList.RemoveAt(Form1.selectedIndex+1);
Form1.formOpen = true;
this.Dispose();
}
At this point we are back to form1, in which we have a timer with timer_tick event. In there we check whether the boolean formOpen is true (which it is set before closing form2). Inside the if statement we clear the listbox and add each rule from the ruleList (previously edited in form2) to the listbox, then sets the formOpen back to false so it doesn't get executed all the time:
if (formOpen)
{
lbRules.Items.Clear();
foreach (string item in ruleList)
lbRules.Items.Add(item);
}
formOpen = false;
Now this is really weird, and at this point makes absolutely no sense to me, since I tried debugging it for over an hour, trying different ways, which also led me to mysterious wonders of WHY TF IT WORKS WHENEVER IT WANTS...
So this works randomly, like it would work the first time, the second and third times it won't. Or vice versa. It's all random.
Strangely, I tried adding a breakpoint on the
lbRules.Items.Add(item);
in the foreach loop, so it stops on each item. And I actually saw the changed rule getting added from the ruleList into the listBox, however in the end it was not there.
And weirdly enough, I also tried adding the text from form2 in the listBox in form1, without using a list, but for whatever odd reason, I use the int selectedIndex, which gets the index of the selected item from the BtnModify_Click event to insert the text in that particular index, but this very index gets RANDOMLY set to bloody 0 after form2 closes.
hence, it again works from time to time, because at some tries it doesn't get set to 0 and it works.
if (formOpen)
{
selectedRule = Rules.saveRule;
lbRules.Items.Insert(selectedIndex, selectedRule);
lbRules.Items.RemoveAt(selectedIndex+1);
}
formOpen = false;
I don't assign value to this integer ANYWHERE else in the code.
I really tried digging some sense, but I hit a solid hard rock.
Any help appreciated!
And thanks for the time!
edit1:
as requested - rest of the timer method
private void Timer1_Tick(object sender, EventArgs e)
{
foreach (string text in ws.messages)
message = text;
if (ws.messages.Count > 0)
{
if (message.Contains("comp"))
{
Complaints();
message = String.Empty;
ws.messages.Clear();
}
}
if (formOpen)
{
lbRules.Items.Clear();
foreach (string item in ruleList)
lbRules.Items.Add(item);
}
formOpen = false;
}
I would change your code to the following:
if (formOpen)
{
formOpen = false;
lbRules.Items.Clear();
foreach (string item in ruleList)
lbRules.Items.Add(item);
}
The issue with having the formOpen = false; outside the if statement is that there is a chance that once the user clicks the Save button the timer could be about to execute the formOpen = false instruction setting it to false making the code inside the If statement to never be executed.
I truly believe this is not random but just a timing issue due to complicated logic.
If I were you, I'd do a couple things:
Use a separate class for data exchange between forms, avoid using public static (I assume) form members for this.
Instead of a timer, subscribe to the Form.Closed event of RulesForm
This might make code flow a bit more predictable and allow you to find errors more easily.
Better yet, use the following pattern:
class Form1
{
private void BtnModify_Click(object sender, EventArgs e)
{
var ruleData = ..... //get current rule data
var rulesForm = new Rules();
rulesForm.SetData(ruleData); //pass initial state to the form
rulesForm.SaveChanges = this.ApplyRules; //pass a method which will be called on save
rulesForm.Show();
}
private bool ApplyRules(RuleData ruleData)
{
//do whatever you like with the rules here
return true;
}
}
class RuleForm
{
public void SetData(RuleData ruleData)
{
//initialize fields, etc
}
public Func<RuleData, bool> SaveChanges { get; set; }
private void BtnSave_Click(object sender, EventArgs e)
{
var ruleData = .... //get data from form fields
if(this.SaveChanges(ruleData))
this.Close();
}
}
class RuleData
{
//whatever data you need
}
I'm a first semester c# student and trying to learn over summer break to be ahead when school starts back up in the fall.
I have a multiform application that I'm using lists to store information and statistics.
On form one I have a list that stores a bowler's name. This form is called MainForm. On the second form, opened from a button on MainForm, I have two text boxes for first name and last name and an 'add bowler' button. I want to be able to input the information in the text boxes and have this update the list that I created on MainForm.
The second form is called AddBowlerForm. I've been working on this for a couple of days, and I've followed so many tutorials and youtube videos that I'm almost lost on where I started.
The code I have at the moment on MainForm:
private void MainForm_Load(object sender, EventArgs e)
{
//create list to hold names of bowlers
List<string> listBowlers = new List<string>();
ReadBowlers(listBowlers);
DisplayBowlers(listBowlers);
}
private void buttonAddBowler_Click(object sender, EventArgs e)
{
//create instance of AddBowlerForm
AddBowlerForm addBowler = new AddBowlerForm(this);
if (addBowler.ShowDialog(this) == DialogResult.OK)
{
listBowlers.items.add(addBowler.Bowler());
listBoxBowlers.Items.Add(AddBowlerForm.Bowler());
}
//Display the form.
addBowler.ShowDialog();
The relevant code from AddBowlerForm:
public AddBowlerForm(MainForm mainForm)
{
InitializeComponent();
this.mainForm = mainForm;
}
public string Bowler
{
get
{
return textBoxFirstName.Text + textBoxLastName.Text;
}
}
private void buttonAdd_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
}
I truly would appreciate any and all help on this. I've read more web pages in the last couple of days than I can remember, but not sure where I'm going wrong.
You need something called a Handler.
A handler is like a promise that is given to an object, which says "When you call this method, there will be one to handle it" even when the method doing the handling is completely out of scope from the object invoking the handler.
So, your NewBowler form needs to include in its constructor a delegate which points back to a method which requires the input you need. So, when you click the submit button on your form, the method that button calls will raise the "NewBowlerHandler()" event which you provided in the constructor.
Then, whatever method back on your MainForm which actually does the adding of the bowler will handle the input provided by the form.
If you need more resources on delegates, handlers, and event, you can find documentation here EventHandler Delegates
i'm new to the programming went through few tutorials and sample projects and then started to create my own text based adventure game with some UI.
So what i'd like to achieve with the beginning of my project is, when user launches exe, i'd like to greet them with a username input screen with Start and Exit buttons and then close that form, launch a new form which i'll put in the game's main interface.
So, when i click the "Start" Button, it'll read the username from the textbox, save it to a string, close the form and launch a new form with also using the name screen in the game's main interface.
My question is, How can i link the start button from the below code to a new Form, also closing the current AUJFM_Login form, which will also be able to read the string username.
I have tried few things but after a few attempts, i just left it with the button functions. It's not much but here is the basics of it:
The Greeting screen will be called AUJFM_Login, and the main interface will be called AUJFM.
namespace AUJFM
{
public partial class AUJFM_Login : Form
{
public AUJFM_Login()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
string UserName = nameBox.Text;
}
private void btnExit_Click(object sender, EventArgs e)
{
Application.Exit();
}
}
You can try the code below for the “Start” button click. I added a method to check the user name as it seems like sending an invalid user name to the next form is simply a waste of time. You will have to adjust this method to check for the valid users. Hope this is what you are looking for.
private void btnStart_Click(object sender, EventArgs e) {
string userName = nameBox.Text;
if (ValidUserName(userName)) {
SecondForm nextForm = new SecondForm(userName);
nextForm.Show();
this.Hide();
} else {
// user name not valid
}
}
private bool ValidUserName(String userName) {
// logic to check if user name is valid
return true;
}
Then in the second form constructor, change the signature to accept the user name string.
public SecondForm(string userName) {
InitializeComponent();
textBox1.Text = userName;
}
If you have a form for the main window (Let's call it MainForm),
you can do:
MainForm mainForm = new MainForm();
mainForm.Show();
The main window would then appear.
To close the login form, you could do
this.Hide();
Since closing the form from which the application runs would close the entire application.
I am working on a program that generates a PDF file. Before the final generation of the file, I want to give the user the option to edit a portion of the file (The title of the graph that is about to be created). I want this to show up in a new form when the user clicks a button to export the PDF. Here is an outline of what I am trying to do...
private void button4_Click(object sender, EventArgs e) // Test PDF Code!
{
Form2 NewPDF = new Form2(chart3.Titles[chart3.Titles.IndexOf("Header")].Text.ToString().Substring(0, chart3.Titles[chart3.Titles.IndexOf("Header")].Text.ToString().Length - 4));
NewPDF.Show();
if (NewPDF.Selected == true)
{
// Create PDF, open save file dialog, etc
}
}
And here is the Form that is being opened by this button click...
public partial class Form2 : Form
{
public bool Selected
{
get;
set;
}
public String GraphName
{
get;
set;
}
public Form2(String FileName)
{
InitializeComponent();
textBox1.Text = FileName;
GraphName = FileName;
Selected = false;
}
public void button1_Click(object sender, EventArgs e)
{
GraphName = textBox1.Text;
this.Selected = true; // After the button is selected I want the code written above to continue execution, however it does not!
}
}
As of now, when I click on the button in Form2, nothing happens, there is something about the communication between the two Forms that I am not understanding!
You should change your Form2.GraphName like below
public String GraphName
{
get { return textBox1.Text }
}
then change your new Form2 creation like below, test it since I haven't run this through VS, but should work :)
private void button4_Click(object sender, EventArgs e) // Test PDF Code!
{
// why on earth were you doing .Text.ToString()? it's already string...
Form2 NewPDF = new Form2(chart3.Titles[chart3.Titles.IndexOf("Header")].Text.Substring(0, chart3.Titles[chart3.Titles.IndexOf("Header")].Text.Length - 4));
// show as a dialog form, so it will wait for it to exit, and set this form as parent
NewPDF.ShowDialog(this);
if (NewPDF.Selected == true)
{
// get the name from the other form
string fileName = NewPDF.GraphName;
// Create PDF, open save file dialog, etc
}
}
The answer to your problem is quite simple.
NewPDF.Show();
Show() does not pause execution of the calling form. Therefore, the check underneath that that verifies the Selected property if true will never execute properly, since that check is reached and verified just as the form starts appearing. ShowDialog() does pause execution and waits for the called form to close.
That aside; I would recommend one of two other ways to communicate between forms;
Use a global variable. Declare a variable holding the graph's name somewhere in a public module. Call the dialog that asks the user to input a name with ShowDialog(), since that pauses execution of the calling form until the called form returns a result.
if(Form.ShowDialog() == DialogResult.OK) {
// Save pdf, using title in global variable
}
Make sure to set the DialogResult in the called form before Close()-ing it.
Pass an instance variable of the calling form to the called name-input form to the constructor and save it. That way, if you expose the graph name property as a public property, you should be able to access it from the called form in the code that closes the form, which is your:
public void button1_Click(object sender, EventArgs e)
{
callingFormInstance.GraphNameProperty = textBox1.Text;
Close();
}
Hope that helps. Cheers!
To make sure that the user name input is valid, I added such callback method to do the verification:
Regex UserNameRE = new Regex(#"^[a-zA-Z]\w*$");
//being called when input box is not focused any more
private void UserNameInput_Leave(object sender, EventArgs e)
{
//pop up a warning when user name input is invalid
if (!UserNameRE.IsMatch(UserNameInput.Text))
{
MessageBox.Show("Invalid User Name!");
this.UserNameInput.Text = "";
this.UserNameInput.Focus();
}
}
The method will be called when user finished their inputting(the method is bounded with the event-"leaving the input box"). It works when user left a invalid User_Name and begin to enter a password.
But it also works when user click another tab, e.g. the Register tab. I don't want this happen. Because the user obviously don't wanna login anymore if he clicks "Register" tab, and my C# app shouldnot pop up a warning box and force them inputting a valid user name again.
How can the C# tell the difference of such 2 situations? It should be easy if I know which object is being clicked.
You will have source of event in object sender in UserNameInput_Leave event.
private void UserNameInput_Leave(object sender, EventArgs e)
{
//sender is source of event here
}
Here's an option:
private void UserNameInput_Leave(object sender, EventArgs e)
{
if (sender.GetType() != typeof(TextBox))
{
return;
}
TextBox tBox = (TextBox)sender;
//pop up a warning when user name input is invalid
if (!UserNameRE.IsMatch(UserNameInput.Text) && tBox.Name == UserNameInput.Name)
{
MessageBox.Show("Invalid User Name!");
this.UserNameInput.Text = "";
this.UserNameInput.Focus();
}
}
I am not sure if there's a right solution for this particular scenario here.
When you add a handler to validate your control on mouse leave, definitely it will be executed first regardless you clicked on another control within the tab or another tab itself.
This normal flow can't be ignored easily. It must be possible by hanlding the message loop yourself but the event based flow, first leave focus, and selected index change (selecting) event will be fired. I would suggest you not to disturb the flow as the validation is client side and pretty fast. Instead of messagebox, I would recommend you to use ErrorProvider and attach to the control whenever required. Also messagebox is quite disturbing and as per your code, you're forcefully making it focus to the textbox again.
How about the following code?
public partial class Form1 : Form
{
ErrorProvider errorProvider = new ErrorProvider();
public Form1()
{
InitializeComponent();
textBox1.Validating += new CancelEventHandler(textBox1_Validating);
}
private void textBox1_Leave(object sender, EventArgs e)
{
textBox1.CausesValidation = true;
}
void textBox1_Validating(object sender, CancelEventArgs e)
{
Regex UserNameRE = new Regex(#"^[a-zA-Z]\w*$");
if (!UserNameRE.IsMatch(textBox1.Text))
{
errorProvider.SetError(this.textBox1, "Invalid username");
}
}
}