C# Do While Message Box is active - c#

I am working on a project in C# that requires user input from a pop-up message box.
I am also trying to have my code perform a series of tasks while the message box is active.
My goal is to have the MessageBox describe the tasks being performed and ask the user to observe and verify that they are being carried out.
I want these tasks to continuously be performed until the user clicks on a response in the MessageBox.
To create my message box, I am using:
MessageBox.Show(string <message>, string <caption>, MessageBoxButton.YesNo)
And the basic structure of what I am trying to do is as follows:
var userInput = MessageBox.Show("Are tasks A, B, C running?", "winCaption", MessageBoxButton.YesNo);
while (// <No response to MessageBox>)
{
// Task A
// Task B
// Task C
if (userInput == MessageBoxResult.Yes)
{
// PASS
// exit while loop
}
else
{
// FAIL
// exit while loop
}
}
I have found that when the MessageBox.Show() occurs & the pop-up window appears, the code seems to hang at that line until the user response is detected.
Is it possible to make this work? If not, are there any alternatives?
Thank you

How about calling MessageBox on separate Thread?
var action = new Action(() =>
{
var userInput = MessageBox.Show("Are tasks A, B, C running?", "winCaption", MessageBoxButtons.YesNo);
if (userInput == DialogResult.Yes)
{
// PASS
}
else
{
// FAIL
}
});
new Thread(new ThreadStart(action)).Start();

MessageBox.Show creates a modal dialog, meaning that execution on the thread stops until it is closed. You'll need to create a new Form that displays instead of using the built in MessageBox.
Once you've created the form, call it like this:
MyForm form = new MyForm();
form.Show(); //Note that this will NOT be modal
Keep in mind that Form does have a way to display it modally called ShowDialog(). It can be a bit confusing, so I'll summarize here:
MessageBox.Show(); //Modal
Form.Show(); //Not Modal
Form.ShowDialog(); //Modal

Related

How to stop Windows Form program execution until text box input is given?

I'm building a windows form application that stores employee information records in a database, including SSN. Next to the textbox where the SSN is input is requested, I have a checkbox that when clicked, shows me the full SSN instead of the last four digits. To ensure that only an administrator is accessing this information, I created a prompt form connected to a MS SQL DB that stores an admin password and would like to ask the user for a password for security purposes. Also, i'd like to be able to call this form whenever needed. I successfully implemented it but would like to add a feature that allows for 3 tries. Is there a way to stop the program execution and keep prompting the user for input in a textBox?
output is a variable that stores the result of the 'SELECT' query that gets the password.
confirmation is the Accept Button.
The only option i could think of forcing input was calling a new form. Only problem is, this code is inside the form and my gut tells me that's not the answer to this problem. I must be missing something.
confirmation.Click += (sender, e) => {
//If Password is correct.
if (textBox.Text == output)
{
isCorrect = true;
Pprompt.Close();
}
else
{
isCorrect = false;
//While the password is incorrect.
while (isCorrect == false)
{
//textBox.Text = "";
if (textBox.Text == output)
{
isCorrect = true;
Pprompt.Close();
break;
}
tryCount++;
if (tryCount == 3)
{
MessageBox.Show("Access Denied.");
break;
}
}
}
}
What I'd like to happen is for the form to keep asking me for input until the try limit is exceeded.
You cannot have the loop inside the click handler, because the UI freezes while it is running and the user does not get the opportunity make any entries.
Process only one entry and process the next when the user clicks the button again.
confirmation.Click += (sender, e) => {
if (textBox.Text == output) // Password is correct.
{
isCorrect = true;
Pprompt.Close();
}
else
{
isCorrect = false;
textBox.Text = "";
tryCount++;
if (tryCount == 3)
{
MessageBox.Show("Access Denied.");
Pprompt.Close();
}
}
}
Unless you are using multi-threading or async/await, the following is true:
Winforms is event based. I.e., if no event handler is running, no code is running.
If code (i.e. an event handler) is running, the user interface (UI) is frozen and the user cannot make any input. He cannot enter text or click any buttons, cannot scroll lists and cannot resize or move the window.
While an event handler is running, no other event handler will ever be called. I.e., an event handler will never be interrupted by another one. This prevents you from having to deal with multi-threading issues unless you are using multi-threading explicitly.
If an event should be fired (e.g. a timer tick) while an event handler (e.g. a button click handler) is running, the execution of the event handler associated to this new event will be deferred until after the first event handler returns.

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;
}
}

Halt execution until a response is given

I have scripts that run on request and are compiled using CodeDomProvider. Here's an example of one:
var yes = SendYesNo();
if (yes)
// Do something
else
// Do something else
Now. SendYesNo displays a box with input from the user. I want to halt the script on that line, until a response is set. And then, take the response and apply it to the variable and continue the execution. So far I've used await/async, but I dislike this idea. Is it possible with something else?
You could use a modal window that returns your parameter. You could either use a standard MessageBox or a customized Form if the input required is more complex.
Something like:
public class SomeForm : Form
{
public bool yesNo
{
get
{
return yesNo;
}
set
{
//set value according to your logic
}
}
}
and in your main Form call it like:
using (var form = new SomeForm())
{
if (form.ShowDialog() == DialogResult.OK)
{
var yesNo = form.yesNo;
if (yes)
// Do something
else
// Do something else
}
}
in case it's just a Yes / No MessageBox you can refer to:
How do I create a message box with "Yes", "No" choices and a DialogResult?

Hide form instead of closing when close button clicked

When a user clicks the X button on a form, how can I hide it instead of closing it?
I have tried this.hide() in FormClosing but it still closes the form.
Like so:
private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
Hide();
}
}
(via Tim Huffman)
I've commented in a previous answer but thought I'd provide my own. Based on your question this code is similar to the top answer but adds the feature another mentions:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
Hide();
}
}
If the user is simply hitting the X in the window, the form hides; if anything else such as Task Manager, Application.Exit(), or Windows shutdown, the form is properly closed, since the return statement would be executed.
From MSDN:
To cancel the closure of a form, set the Cancel property of the FormClosingEventArgs passed to your event handler to true.
So cancel then hide.
Based on other response, you can put it in your form code :
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
Hide();
}
}
According MSDN, the override is preferred:
The OnFormClosing method also allows derived classes to handle the
event without attaching a delegate. This is the preferred technique
for handling the event in a derived class.
If you want to use the show/hide method I've actually done this myself for a menu structure a game I've recently done... This is how I did it:
Create yourself a button and for what you'd like to do, for example a 'Next' button and match the following code to your program. For a next button in this example the code would be:
btnNext.Enabled = true; //This enabled the button obviously
this.Hide(); //Here is where the hiding of the form will happen when the button is clicked
Form newForm = new newForm(); //This creates a new instance object for the new form
CurrentForm.Hide(); //This hides the current form where you placed the button.
Here is a snippet of the code I used in my game to help you understand what I'm trying to explain:
private void btnInst_Click(object sender, EventArgs e)
{
btnInst.Enabled = true; //Enables the button to work
this.Hide(); // Hides the current form
Form Instructions = new Instructions(); //Instantiates a new instance form object
Instructions.Show(); //Shows the instance form created above
}
So there is a show/hide method few lines of code, rather than doing a massive piece of code for such a simple task.
I hope this helps to solve your problem.
Note that when doing this (several answers have been posted) that you also need to find a way to ALLOW the user to close the form when they really want to. This really becomes a problem if the user tries to shut down the machine when the application is running, because (at least on some OS) this will stop the OS from shutting down properly or efficiently.
The way I solved this was to check the stack trace - there are differences between when the user tries to click the X vs when the system tries to end the application in preparation for shutdown.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
StackTrace trace = new StackTrace();
StackFrame frame;
bool bFoundExitCommand = false;
for (int i = 0; i < trace.FrameCount; i++)
{
frame = trace.GetFrame(i);
string methodName = frame.GetMethod().Name;
if (methodName == "miExit_Click")
{
bFoundExitCommand = true;
Log("FormClosing: Found Exit Command ({0}) - will allow exit", LogUtilityLevel.Debug3, methodName);
}
if (methodName == "PeekMessage")
{
bFoundExitCommand = true;
Log("FormClosing: Found System Shutdown ({0}) - will allow exit", LogUtilityLevel.Debug3, methodName);
}
Log("FormClosing: frame.GetMethod().Name = {0}", LogUtilityLevel.Debug4, methodName);
}
if (!bFoundExitCommand)
{
e.Cancel = true;
this.Visible = false;
}
else
{
this.Visible = false;
}
}
This is the behavior of Modal forms. When you use form.ShowDialog() you are asking for this behavior. The reason for this is that form.ShowDialog doesn't return until the form is hidden or destroyed. So when the form is hidden, the pump inside form.ShowDialog destroys it so that it can return.
If you want to show and hide a form, then you should be using the Modeless dialog model
http://msdn.microsoft.com/en-us/library/39wcs2dh(VS.80).aspx
form.Show() returns immediately, you can show and hide this window all you want and it will not be destroyed until you explicitly destroy it.
When you use modeless forms that are not children of a modal form, then you also need to run a message pump using Application.Run or Application.DoEvents in a loop. If the thread that creates a form exits, then the form will be destroyed. If that thread doesn't run a pump then the forms it owns will be unresponsive.
Edit: this sounds like the sort of thing that the ApplicationContext is designed to solve. http://msdn.microsoft.com/en-us/library/system.windows.forms.applicationcontext.aspx
Basically, you derive a class from ApplicationContext, pass an instance of your ApplicationContext as an argument to Application.Run()
// Create the MyApplicationContext, that derives from ApplicationContext,
// that manages when the application should exit.
MyApplicationContext context = new MyApplicationContext();
// Run the application with the specific context.
Application.Run(context);
Your application context will need to know when it's ok to exit the application and when having the form(s) hidden should not exit the application. When it's time for the app to exit. Your application context or form can call the application context's ExitThread() method to terminate the message loop. At that point Application.Run() will return.
Without knowing more about the heirarchy of your forms and your rules for deciding when to hide forms and when to exit, it's impossible to be more specific.

C# Form Application - Modal Dialogs Have Wrong Parent

I have an application which has an asynchronous operation built into it that loops over a large number of items and performs lengthy calculations on each item, as this occurs certain conditions will cause the application to pop up a modal dialog for user input. Interestingly, I noticed while running this today that in one application instance the modal dialogs somehow got the wrong parent form- rather than providing a modal block to my application the dialogs had taken a Digsby chat window as their parent.
The Digsby window that they became children of popped up around the same time as the first dialog was created (possibly the exact same time) and it would seem that they threads somehow crossed one another because the Digsby window became completely blocked until the async operation completed. I do not know how this is possible considering how per-process threading works, but it certainly did happen. What would cause such a bug? The application is C# .NET 3.5 with Windows Forms running on Windows XP, by the way.
Here's the async code in a nutshell:
Action<List<ClubListing>> a = delegate(List<ClubListing> list)
{
for (int i = 0; i < list.Count; i++)
{
var cl = list[i];
if (cl.MatchingClubListing == null)
{
var compare = CompareNames(cl.Club.Name);
if (compare.Any(c => c.Value == 0 && c.Key.Club.State == cl.Club.State))
{
var match = compare.First(c => c.Value == 0 && c.Key.Club.State == cl.Club.State);
compareDialog.ClubA = cl.Club;
compareDialog.ClubB = match.Key.Club;
DialogResult dr = compareDialog.ShowDialog();
if (dr == DialogResult.Yes)
{
cl.MatchingClubListing = match.Key;
match.Key.MatchingClubListing = cl;
}
else if (dr == DialogResult.Abort)
{
break;
}
}
}
this.Invoke(new MethodInvoker(delegate()
{
this.prbOperationProgress.Value = i;
}));
}
};
AsyncCallback callback = new AsyncCallback(SaveAndUpdate);
var result = a.BeginInvoke(this.lbxLiveClubs.Items.Cast<ClubListing>().ToList(), callback, null);
Add the parent dialog as argument to compareDialog.ShowDialog(). Eg:
Form parent = ...;
compareDialog.ShowDialog(parent);
Just as you're Invoking your ProgressBar update, you need to Invoke() the showing of your dialog.
It looks like you are showing your compare dialog in the worker thread. I think you may be okay if you use a call to Invoke to show your dialog.

Categories

Resources