C# Stop the flow of the program and reset it without restarting - c#

I am writing a simple WindowsForm program with radiobuttons, buttons, and a customary implemented InputBox.
Relevant program logic: I click one of the radiobutons from the groupbox -> enable button -> clicking button initiates custom inputbox asking for 1 value and Yes/Cancel buttons.
|
V
If Yes button clicked -> proceed with logic flow
If Cancel button clicked -> popup window appears ("Your input was cancelled, do you want to exit application?") with yes/no buttons
|
V
If Yes button clicked -> Exit the program
If No button clicked -> apply the same logic as if Reset button is clicked, which would reset the whole program without restarting it <---------This is what I am trying to achieve (all relevant methods are provided below)
What is the problem?
When I simply click Reset button, it applies all needed actions and stops, waiting for my further input. This is the exact result I am trying to achieve when I click No button in the popup window I mentioned above.
However, this is not the case. During the debug mode, after I clicked No button, it goes through the entire logic of the Reset button like I wanted, BUT right after that, it goes into the IF statement (marked in my buttonGetWorkHours_Click method). I don't want that, I want it to stop the flow after applying the logic of Reset button and waiting for my input (radiobutton/button click).
What I tried
I have searched through several threads here in SO and tried implementing several suggestions. The results of these suggestions are commented out inside inputBoxProcedure method. Also, I was looking for similar posts, which would give me the right idea. But they state that it is impossible without reloading. Based on that thread, I thought about implementing extra variable to use for checking if reset logic was running, but seems unnecessarily complicated.
ULTIMATE QUESTION:
I saw a test executable, so I know it is POSSIBLE, unlike what posts and threads were saying. Can you please point me in a right direction of how to proceed with it?
Relevant code snippet methods
For the sake of saving everyone's time I will include only methods relevant to my question.
private void buttonGetWorkHours_Click(object sender, EventArgs e)
{
if (radioButtonJobStatusFull.Checked)
{
inputBoxProcedure("Enter the total hours worked by the full time employee for the week", "40");
}
else if (radioButtonJobStatusPart.Checked)
{
inputBoxProcedure("Enter the total hours worked by the part time employee for the week", "30");
}
//if, else if, else, unrelated to the lines above
if() //<----------------the logic goes here after going through the whole Reset button logic
{}
else if()
{}
else()
{}
}
private void buttonReset_Click(object sender, EventArgs e)
{
//clear all radiobutton selections
//set all strings to empty
//disable several buttons and groupboxes
//hide several labels
}
private void inputBoxProcedure(string text, string defaulttext)
{
InputBoxResult result = InputBox.Show(text, "Hours Entry", defaulttext, new InputBoxValidatingHandler(inputBox_Validating));
if (result.OK)
{
labelHoursWorked.Text = result.Text.Trim();
}
else
{
if (MessageBox.Show("Input was cancelled. Do you wish to quit the application?", "Input Cancelled", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
{
Close();
}
else
{
buttonReset_Click(this, new EventArgs());
//Form fr = new Form();
//fr.Show();
//this.Close();
//Application.Restart();
}
}
}

Try changing the inputBoxProcedure to this:
private bool inputBoxProcedure(string text, string defaulttext)
{
InputBoxResult result = InputBox.Show(text, "Hours Entry", defaulttext, new InputBoxValidatingHandler(inputBox_Validating));
if (result.OK)
{
labelHoursWorked.Text = result.Text.Trim();
}
else
{
if (MessageBox.Show("Input was cancelled. Do you wish to quit the application?", "Input Cancelled", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
{
Close();
}
else
{
buttonReset_Click(this, new EventArgs());
//Form fr = new Form();
//fr.Show();
//this.Close();
//Application.Restart();
return false; // Added
}
}
return true; // Added
}
Notice that the return type void becomes bool and that two lines of return have been added.
In buttonGetWorkHours_Click change:
if (radioButtonJobStatusFull.Checked)
{
inputBoxProcedure("Enter the total hours worked by the full time employee for the week", "40");
}
else if (radioButtonJobStatusPart.Checked)
{
inputBoxProcedure("Enter the total hours worked by the part time employee for the week", "30");
}
Into:
if (radioButtonJobStatusFull.Checked)
{
if (!inputBoxProcedure("Enter the total hours worked by the full time employee for the week", "40"))
return;
}
else if (radioButtonJobStatusPart.Checked)
{
if (!inputBoxProcedure("Enter the total hours worked by the part time employee for the week", "30"))
return;
}
In this way, after a reset, the funtion inputBoxProcedure will return false. When the function returns false the function buttonGetWorkHours_Click will return and thus prevent further excecution.
I hope this helps.

Related

Close current form if dialog results for dialogbox is cancel

I have a Form (frmcustlist).
At one time on this list i scan the list using a dataset and check if it now 0 (no customers left).
At this stage i have an input box pop up (dialog) to ask a new customer name.
If they press OK everything is fine. I also have validation on the box for the input.
However if they press CANCEL, i can get it to escape out of the dialog, but not close frmcustlist that the dialog was called from.
using (inputbox ipfirst = new inputbox("Enter Customer First Name:", "", ""))
{
if (ipfirst.ShowDialog() == DialogResult.OK)
{
newfirstname = ipfirst.answer;
}
else
{
this.Close();
}
}
Now, this.close() doesn't work at all.. so i used return; which stops it going on to ask for the last name and date of birth.. but i want it to stop asking questions (like return) AS WELL as close frmcustlist.
...
Thanks for any advice you can give.
ps. this appears in a few places, but is called in frmcustlist_load as well.. i dont know if that is going to make a difference or not!
Answer was made by STEVE in comments.
As frmcustlist was called itself as a Dialog, i just ended up having to give that dialog a Cancel result.
Final Code that works:
using (inputbox ipfirst = new inputbox("Enter Customer First Name:", "", ""))
{
if (ipfirst.ShowDialog() == DialogResult.OK)
{
newfirstname = ipfirst.answer;
}
else
{
DialogResult = DialogResult.Cancel;
return;
}
}

Registering One Button Press with a GPIO button in C#

The following code is giving me a small issue.
public void ButtonShort()
{
lcd.WriteLine(" K ");
GpioPinValue Readbutton = ButtonS.Read();
if (buttonS == GpioPinValue.Low)
{
Temp = Temp + "K";
}
}
Temp is a list which is empty by default. So every button press should add ONE 'K'.
But it actually registers 'K' multiple times.
What I want is that one button press only registers one 'K'.
Thanks for the help!
I can't directly help you for C#, but had a similar problem once where I used Java with the Pi4J Lib for the GPIO Access.
In there, you have events which are triggered by a changing input pin value. I catched that event and checked in the routine wether the state was high/low, depending on what had to be the actual trigger for counting.
Code in Java was quite straigt forward:
public void handleGpioPinInputStateChangeEvent(GpioPinDigitalStateChangeEvent event) {
if (event.getState() == PinState.HIGH) {
[...]
}
}
[Edit - got interested... :-)]
Perhaps the following code from here will help:
private void buttonPin_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs e)
{
// toggle the state of the LED every time the button is pressed
if (e.Edge == GpioPinEdge.FallingEdge)
{
ledPinValue = (ledPinValue == GpioPinValue.Low) ?
GpioPinValue.High : GpioPinValue.Low;
ledPin.Write(ledPinValue);
}
[...]

Listening event outside MainPage class calling method multiple times on button click event (repetetively)

I have a situation where I have to manage the button click event outside MainPage class (suppose in Class B). Here is the code that I'm using:
namespace TEST
{
public partial class MainPage: UserControl
{
public event Action simpleEvent;
public MainPage()
{
}
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
switch (comboBox1.SelectedItem as string)
{
case "UInt8":
B obj4 = new B(this, fileContent, "UInt8");
break;
case "UInt16":
B obj1 = new B(this, fileContent, "UInt16");
break;
case "UInt32":
B obj2 = new B(this, fileContent, "UInt32");
break;
case "UInt64":
B obj3 = new B(this, fileContent, "UInt64");
goto
default;
default:
MessageBox.Show("check");
break;
}
}
private void ButtonClick_EVENT(object sender, RoutedEventArgs e)
{
// I try to listen outside the class this way.
if (simpleEvent != null)
simpleEvent();
}
}
Class B
{
public B(MainPage Obj, byte[] fileContent, string type)
{
switch (type = Obj.comboBox1.SelectedItem as string)
{
case "UInt8":
{
//do something
break;
}
case "UInt16":
{
//do something
break;
}
case "UInt32":
{
//do something
break;
}
case "UInt64":
{
//do something
goto
default;
}
default:
{
break;
}
}
Obj.simpleEvent += () = > MyMethod(Obj);
}
public void MyMethod(MainPage Obj)
{
// This MessageBox repeats 2 times on second time button click
// and 3 times on 3rd button click .
// It should be called once even on second/third/fourth etc. button clicks.
MessageBox.Show("Repetition check");
}
}
}
The problem is my method is called repetitively. For example, when I click the button the first time it will be called only once (which is good). and if I click the button again the message box pop-up comes up 2 times and again pop-ups 3 times on 3rd attempt.
What I want is to pop-up this message box only once on the click (even if I keep on clicking on the button one after the other click).
EDIT: The new updated code is the actual situation i was trying to make it short so last time i didn't include to much code (because i was not suspecting that part).
What i am trying to do is :
I have to select 1 data type among 4 given data type at run time (uint64/32/16/8)(which will be data type for reading a file ("fileContent" in constructor call), but it's not related to question i asked, so leaving too much discussion on it).After selecting that data type i click the button to display something. (so each time i first i select "data type" from combo box and then i press button to display some data corresponding to that data type then i again select another data type from combo box and then again i press "button" but this time it pop-ups message 2 times, and when i repeat the same 3rd time it pop-ups messagebox 3times).
Suppose first i selected "uint64" in combo box at run time (in the first attempt) and then i click button to display messagebox it will pop-up the message box once.Now without closing the application my second selection to combo box is on uint32 (On second attempt) and again i click to "button" this time this message box is popped 2 times. I don't know why? and on third attempt it pop-ups 3 times.
(1) Why message box repeats ?
Thanks for the help in advance, I really wanna know the reason for it, not able to understand yet.
You're creating a new B object every time your combobox is changed. That adds a new handler every single time, without ever removing the previous handlers. You need to either unsubscribe the old handler when you go to add a new one, or only ever add one handler and simply modify the data that it relies on so that that handler acts appropriately when it fires.

Make a check before closing form?

The code below is in MainFrame.cs and it opens and checks the MovieForm.cs. I want to check if a entered movie title already exist, before a new movie is added to a list. But the problem is, if the title already exist and the messagebox appears, then the MovieForm.cs is already closed and all other data gone and there is no possibilities for the user to change the title to another one! Could this be done in some other way that isn't to complicated? Is there a way to stop the closing of the form? Thanks!
private void btnNewMovie_Click(object sender, EventArgs e)
{
movieForm = new MovieForm();
if (movieForm.ShowDialog() == DialogResult.OK)
{
if (!movieManager.GetMovieFromList(index).Split(',') [0].Equals(movieForm.GetTitle))
{
movieManager.AddNewMovieToMediaLibrary(movieForm.GetNewMovie); // Anropar properties i objektet movieManager
UppdateListboxOfMovies();
}
else
{
MessageBox.Show("Det finns redan en film med titeln " + movieManager.GetMovieFromList(index).Split(',')[0], "Ooops!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
}
You have an opportunity to cancel the form closing:
private void btnNewMovie_Click(object sender, EventArgs e)
{
using (var movieForm = new MovieForm())
{
movieForm.Closing += (s, a) =>
{
if (movieForm.DialogResult == DialogResult.OK)
{
if (!movieManager.GetMovieFromList(index).Split(',') [0].Equals(movieForm.GetTitle))
{
movieManager.AddNewMovieToMediaLibrary(movieForm.GetNewMovie); // Anropar properties i objektet movieManager
UppdateListboxOfMovies();
}
else
{
MessageBox.Show("Det finns redan en film med titeln " + movieManager.GetMovieFromList(index).Split(',')[0], "Ooops!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
// Prevent the form from closing and let the user try again
a.Cancel = true;
}
}
};
movieForm.ShowDialog();
}
}
The movieForm object is still in scope, so you can still access any public data from it. I assume that movieForm.GetTitle is returning correctly. All you need to do now is apply the following correction because at the moment you are just comparing your title with the first title in the list:
if (!movieManager.GetMovieFromList(index).Split(',').Contains(movieForm.GetTitle))
...
That should solve your problem.
Edit: Ok, I misunderstood your problem. You want the form to stay open so that the user can make corrections. Possible solutions:
Solution 1: Pass in the movieManager object into MovieForm through a parameterized constructor. This way you can check the list before closing the form (on the button's click event).
Solution 2: Create a static MovieManager.GetMovieFromList method so that you aren't required to instantiate it.
I hope this makes sense.
You still have the movieForm object. You could do movieForm.ShowDialog() again.
Don't forget to fill in the edit fields again with the values in onShow or similar method.
Move the check/add code inside your MovieForm and then you can simply just call movieForm.ShowDialog(). You could also raise an event to the main form that the movie was added.

C# WinForms: Waiting for a button press inside an infinite loop

I'm making a simple Guess-The-Number game with a GUI. I need to wait on a loop waiting for the user to input a number in a text box and press "OK". How do I wait for an event inside a loop?
Note: I don't want message boxes. This is done in the main window, hence the need to wait for input.
EDIT: I should have explained myself better. I know that there's a loop inside the GUI. What I want is another loop inside a method. Maybe there's a better way to do this. I could code stuff inside the button's event handler, now that I think about it. Although I'd need global variables. Whataver, I'll think about it, but I hope my question is clearer now.
EDIT 2: Sorry that my question wasn't clear and the edit didn't do much help. First of all, the code is too big to be posted here. I'd probably have to post a screenshot of the GUI, so it wouldn't be of much use. Basically, I have two fields, "Max number" and "Number of allowed guesses". The user enters these two and clicks "Play". A new panel becomes available, with a text box and a "Guess" button. The user enters a guess, and the program checks to see if it's correct.
The purpose of the second infinite loop is to avoid global variables. See, each time the user clicks "Play", the game has to generate a new random number as the correct guess. If everything is done inside a method, no problem. But if the "Guess" button's event handler is called multiple times, the number has to be stored as an instance variable of the Form. Sure, it's not big deal, but I think the number should be a property of the method directing the current game, not of the Form.
I'd also have to keep track of the remaining number of guesses outside of the method. Again, it's no big deal. I just want to avoid globals if I can.
Again, I'm sorry that my question wasn't too clear. I'm kind of tired, and I didn't feel like writing too much. If this still isn't clear, then don't bother. I'll think of something.
C# automatically loops infinitely waiting for events until your form is closed. You just need to respond to the button click event.
Jason Down's suggestion is wise, create a new GuessingGame class and add it to your project. I know you're worried about "global variables" (which everyone is taught in school never to use unless you absolutely have to), but think about your design specifications for a minute.
But if the "Guess" button's event handler is called multiple times, the number has to be stored as an instance variable of the Form. Sure, it's not big deal, but I think the number should be a property of the method directing the current game, not of the Form.
As an alternative, store an instance of your GuessingGame class in the form. This is not a global variable! You said so yourself, the point of the game is keep track of the guesses and generate new numbers to guess every time "Play" is clicked. If you store an instance of the game in the form then open another form (e.g. a Help or About box), then the game's instance would not be available (thus, not global).
The GuessingGame object is going to look something like:
public class GuessingGame
{
private static Random _RNG = new Random();
private bool _GameRunning;
private bool _GameWon;
private int _Number;
private int _GuessesRemaining;
public int GuessesRemaining
{
get { return _GuessesRemaining; }
}
public bool GameEnded
{
get { return !_GameRunning; }
}
public bool GameWon
{
get { return _GameWon; }
}
public GuessingGame()
{
_GameRunning = false;
_GameWon = false;
}
public void StartNewGame(int numberOfGuesses, int max)
{
if (max <= 0)
throw new ArgumentOutOfRangeException("max", "Must be > 0");
if (max == int.MaxValue)
_Number = _RNG.Next();
else
_Number = _RNG.Next(0, max + 1);
_GuessesRemaining = numberOfGuesses;
_GameRunning = true;
}
public bool MakeGuess(int guess)
{
if (_GameRunning)
{
_GuessesRemaining--;
if (_GuessesRemaining <= 0)
{
_GameRunning = false;
_GameWon = false;
return false;
}
if (guess == _Number)
{
_GameWon = true;
return true;
}
else
{
return false;
}
}
else
{
throw new Exception("The game is not running. Call StartNewGame() before making a guess.");
}
}
}
This way, all the data related to the game is encapsulated within the class. Hooking up the events is easy in the codebehind of the form:
GuessingGame game = new GuessingGame();
private void btnPlay_Click(object sender, EventArgs e)
{
int numberOfGuesses = Convert.ToInt32(txtNumberOfGuesses.Text);
int max = Convert.ToInt32(txtMax.Text);
game.StartNewGame(numberOfGuesses, max);
}
private void btnGuess_Click(object sender, EventArgs e)
{
int guess = Convert.ToInt32(txtGuess.Text);
bool correct = game.MakeGuess(guess);
if (correct)
lblWin.Visible = true;
if (game.GameEnded)
{
// disable guess button, show loss label
}
}
You should probably look for a book to actually learn windows programming.
The very basics:
1) There is already an infinite loop deep down in the windows code somewhere. Any windows program is constantly looping and scanning for input.
2) Once input is found, this loop fires off an Event.
3) Your mission, should you choose to accept it, is to write event handlers to handle those events.
you are most likely doing it wrong as it has already been pointed out, but you can use this
Application.DoEvents();
to process events when you are on an actual loop
to do it the right way
- don't use a loop
- use an edit box for the input, then a button
- implement the button onclick event
Yes, and What if I am waiting for Speech events, it could happen anytime event when a function is running, I need to handle that without recursively call a function

Categories

Resources