I am quite new to Visual Studio (Express) and C#. I have made a windows form that accepts some user input then displays that input in a Message Box (that automatically comes with an "OK" button that closes the Message Box when clicked).
Instead I would like the user input collected by the first form to be displayed in a new form that displays a message (label), shows the input, and offers a choice of two buttons: one to accept and one to go back and change the input.
I have NO idea how to do this and any advice is appreciated.
Sounds like you need a confirm Message or something similar.
The MessageBox class offers this functionality.
DialogResult btn = MessageBox.Show("your message",
"your title",
MessageBoxButtons.OKCancel,
MessageBoxIcons.Question);
if(btn == DialogResult.Cancel)
// User canceled, return to the string editor
else
// User confirmed, do you work
If you prefer there is also an enum for MessageBoxButtons.YesNo with corresponding DialogResult.Yes and DialogResult.No
See here for a reference on MessageBoxButtons
See here for a reference on MessageBoxIcons
What you need is to somehow pass the information from the first form to the second. This can be done by setting properties on the child form, either through individual properties (strings, ints, etc.) or by a complete data structure (object). The input form collects the information, creates the sub child form, sets properties on it, then displays the form. Many other ways to do this, but start with the simple and then build up to the complex.
If you need to pass some data to your second form, create property/properties on that form, or provide data via constructor parameters. Also assign DialogResult property for two buttons on second form. Set DialogResult.OK to button which will accept input. Verify value returned by second form, when you show it as dialog and do appropriate actions:
using(SecondForm secondForm = new SecondForm()
{
secondForm.Data = yourData;
if (secondForm.ShowDialog() != DialogResult.OK)
{
// go back and change input
return
}
// accept input
}
So your Form2 needs to have some value, provided by whatever creates it, for it to exist. There should never be an instance of Form2 without that information. That tells you that it should be in that form's constructor (as opposed to a property on that form).
This means that in Form1 you will have something like this:
string someData; //populate based off of user input
Form2 childForm = new Form2(someData);
//then hide current form and show child form
In Form2 you probably already have a constructor, you just need to modify it to something like:
public Form2(string someData) //TODO give better parameter name
{
someLabel.Text = someData;
}
Next we need to deal with the child form going back to the parent form. I feel the preferable way to deal with this is using events. The form has a FormClosing event that you can attach to; this will allow your parent form to run some code when the child form is closed.
string someData; //populate based off of user input
Form2 childForm = new Form2(someData);
childForm.FormClosing += (sendingForm, args) =>
{
this.Show();
bool result = childForm.DidUserAccept;
}
Here I used a property on the child form DidUserAccept, for whether the user accepted or declined the value. We'll need to define that in Form2:
public bool DidUserAccept {get; private set;}
In the button click handlers for accept/cancel you can set the result accordingly and then close the form (closing will trigger the closed event and runt he relevant code in Form1.
Related
I have a form window that has a button, which on click creates an instance of a different form window and launches it. Something like this:
private void button_onclick(stuff)
{
form f = new form2;
form2.showdialog();
}
This form2 has a similar button that launches form3, and so one.
What I would like to do is to create an instance of all my forms in the first from window. I would like to show the first form, have it deactivate but not close, return a value, and then show another one. I am trying to facilitate a "next button" and "back button". In particular, I want to make the back button return to the same instance of the form that called it. I am having a problem because the ShowDialog method I am using suspends the calling form until the called form closes. I want to return to the calling form without closing it, preferable with some kind of return value so I can use some logic to determine what happens next.
Some pseudo code of what I would like to do:
form2;
form3;
form4;
while (form1 not closed)
{
int test;
test = form2.method();
switch test
{
case test == 1
test = form3.method(); break;
case test == 2
test = form4.method(); break;
.
.
.
} //end of while loop
I would appreciate a point in the right direction.
Consider showing/hiding container controls on a single form, rather than different forms. Also, check out some of these examples online for ideas on how to implement back/next:
http://msdn.microsoft.com/en-us/library/7k3w6w59.aspx
http://www.codeproject.com/Articles/4005/A-NET-Wizard-control
I want to do something like the answer here:
How can I close a login form and show the main form without my application closing?
...but I want to pass a value selected on the initial form to the next (main) form. If I call an overridden constructor on the main form, where do I store the value in the meantime (between the initial form being dismissed and the main form being called)?
OTOH, if, instead of using the program.cs file to do this, I create the "initial form" inside the main form's Load() event (is there a better place), I could do something like this, but admittedly it seems rather kludgy:
0) Set the main form's size to 0,0 to hide it
1) Show the "initial" form/modal dialog, and store the value the user selects (in a button click event) in a form-global variable
2) Once the initial form/modal dialog closes, set the main form's size back to what it should be (unless modal result <> OK, in which case I close the main form and the app)
I know there's a better way to do this...
You don't have to pass a value to the main form. Just like your link explains, open your main form first. Then your main form can open the other form. This other form can place the information in a public property that the main form can access. Since the main form controls the lifetime of this other form, the main form gets the information held in the other form's public property, then closes the other form.
string myVariable;
using (OtherForm otherForm = new OtherForm())
{
otherForm.ShowDialog();
myVariable = otherForm.OtherVariable;
}
Try using ApplicationContext (System.Windows.Forms.ApplicationContext). You can show multiple forms as shown in the example in the following MSDN thread. And regarding data,you can have a common data object which is created once and the forms are instantiated with the data object passed to them before showing them.
http://msdn.microsoft.com/en-us/library/system.windows.forms.applicationcontext%28v=vs.100%29.aspx
When Form2 is closed, via it's X button, the Main form is sometimes hidden as well, but not always. Often times the Main form is hidden after initial 'newForm' button click and other times many open-close operations are required before the Main form gets hidden on Form2's closing. Why is this happening? Why is it irregular?
This is a small test code for a larger application I'm working on. In that application a thread continuously reads the network stream and when a particular message is encountered a modal form is displayed. The user can close that modal form or it can be told to close itself by a different network message. In this event, to give the user some time to view the data that the form is displaying I implemented a delayed form closing for that form. When the form is running its delay closing code, another message can come in over the network that will open up a new instance of this form in which case, I observed, that once the timer of the original form runs out, the original form is left displayed until the new instance is closed. Calling Hide in the FormClosing event handler closes the original form if more than one instances of it are running, but it has this side effect of hiding the entire application (the Main form) when the last instance of this form is closed, either by the user or by the delayed closing code. And again, the entire application is not always hidden, but it does happen.
//Main form's 'newForm' button
private void btn_newForm_Click(object sender, EventArgs e)
{
Form2 f = new Form2();
f.ShowDialog();
}
public partial class Form2 : Form
{
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
Hide();
}
}
Update (from the application I'm working on):
The problem is shown visually below. The top part of the picture, labeled "A", represents the situation where the first modal dialog (greyed out) was instantiated and it is in the process of being auto closed after 4 seconds have elapsed. The second instance (blue window heading) is active and awaiting input. In the lower part of the picture, labeled "B", the counter to closing of the first instance has completed, yet the first instance remains visible. Adding Hide does not change picture "A" but picture "B" would only be showing the active modal dialog, which is what I want. If Hide is not used and we have the case shown in "B", once the active modal dialog is closed the inactive dialog will disappear together with the active one, but no sooner. At this time my main form will be hidden as well, sometimes.
Your main form doesn't get hidden, it disappears behind another window. The flaw in your code is that for a brief moment none of your windows can get the focus. Your main window can't get the focus, it got disabled by your dialog and won't get re-enabled until the dialog is fully closed. Your dialog can't get the focus, you hide it. So Windows goes looking for another window to give the focus to and can only pick a window owned by another application. Like Visual Studio, nice and big so your main window is well covered by it.
Not sure what you are trying to do, it doesn't make sense to call Hide() since the dialog will close a couple of microseconds later. Just delete the statement.
I am not sure if I am right but maybe you forgot to add e.Cancel = true; to your closing event.
Second, I think using a modal form is only usefull when you expect an action like OK or CANCEL from user, that is where DialogResults comes handy. It sounds strange if this happens time to time not all the time! maybe you can try like this:
//Main form's 'newForm' button
//Define form in your mainform
private Form2 f;
private void btn_newForm_Click(object sender, EventArgs e)
{
if(f != null) { f.Show(); return; }
f = new Form2()
f.FormClosing += delegate { f.Hide(); };
f.Show();
}
I know the topic is quite old, but I recently had to look for answers for this precise question.
Why hiding the (child modal) form instead of closing it ?
I may be wrong, but I think that in some cases, hidding the modal child form instead of closing it is sometimes useful.
For example, I'm using a class that is a custom tree of grids. Think of something like an Excel Document with multiples tables (sheets) and each table can have child tables. A very powerful manner to store datas that can be used by multiple objects and multiple forms at a time.
Now, this "TreeTable_Class" object has an inbuilt custom form that actually shows the content of one of its tables at a time in a GridView, and you can select which table to show by selecting it in a Treeview. You can see here that the "Database Editor" is actually and MDI Form that can load the Form from any TreeTable_Class.
And this is the Form I use to edit the content of a Cell for a given (selected) Table (I've chosen another cell with long text content from another table in this database)
Now, when you choose to close the custom form instead of hiding it, that form will be unaccessible, you can't show it anymore, and you get an exception (no instance of the object) Somewhat, it isn't disposed yet (so the check If MyForm Is Nothing Then... is useless) I know I have to implement the GarbageCollector and dispose the Child Form manually, but it's outside the scope of this topic.
Anyway, my class could use a large amount of memory, of datas, and if I had to rebuilt ALL the contents each time I want to show a new instance of that form, that would be a large amount of workload in my application. That's why I have chosen to hide the form instead of closing it until the main application exits or when a specific CloseFormAndDispose() method is explicitly called, either by the program, or if I make this option available for the user via an user interface.
Workaround try :
This is the workaround I've found to override the "form replaced by another because none of the parent/child ones could be retrieved" :
Sorry, I'm in VB.. but you can use a tool to convert this to C#, or do it manually, it's pretty simple..
// This is the child, a Cell Editor that can edit the content of a Cell.
Protected WithEvents _CellEditor As CellEditor_Form = Nothing
This Editor form is a member of TreeTable_Form, a form that can actually show and edit the content of the whole Database File (a single file)
And this TreeTable_Form class contains a routine that handles CellEditor closing event
Public Partial Class TreeTable_Form
// Sorry. The "WithEvents" in C# is a litte bit complex to me... So, in VB :
Protected WithEvents _CellEditor As CellEditor_Form = Nothing
// ...
// CellEditor handling method (I used a Code converter...) :
// The original VB declaration is :
// Protected Sub RecallFormAfterCellEditorHidden() Handles _CellEditor.Closed
// You'll have to write specific Event handler for _CellEditor object declared above...
protected void RecallFocusAfterCellEditorHidden()
{
Application.DoEvents();
this.Focus();
}
End Class
This tiny protected void RecallFormAfterCellEditorHidden() method in your Class (if you are using a class that contains Forms) or in your Main From, assuming that your main form contains the child forms (dialogs) will try to force the focus on your Application or MainForm...
By the way, TreeTable_Form is actually a component of TreeTable_Class. The later is an object that can be used anywhere you want. In a Main Form Application, in another Class, in a dialog, anywhere... and could be passed by reference to share its contents between several items. And this TreeTable_Class contains a RecallFocusAfterTreeViewerHidden() method that handles the closing of that form. That means, the Form or Application that actually uses the class will get the focus each time you close the its child Form. I've made it that way to get an object that could be used anywhere
We still get problems !
However, this method will make your application flicker a bit each time you close your child dialog, and doesn't succeed at 100% ! Sometimes, my parent form still disappear from screen and gets struck behind another window. Alt+TAB wont helt either. But this happens less than without this method trick. I don't have any better answer at this time, still searching... I'll come back here if I find out how. I'm using this custom made application in my work to write memos during meetings for example, and produce PV (procès verbal - french sorry) in PDF or DOCx on the fly...
And I'm sorry, I'm in VB, not C#. Hope this helps a little, until we find a better workaround for this...
I am making one application in which there is one main Form FormMain and one helper Form FormHelper.
For understanding, take an example that in FormMain the user is typing in the orders and frequently the user wants to open the FormHelper and fill some values in it.
When the order is saved, the values in FormMain is saved as well as FormHelper.
What I did was make the FormHelper a field in the definition of FormMain :
public partial class FormMain : Form
{
FormHelper BillsForm;
}
And, in the constructor :
public FormReceiptNew(string ReceiptNo)
{
InitializeComponent();
BillsForm = new BillsForm();//just once
}
Now suppose that the user, while filling the FormMain, wants to enter some values in FormHelper, he/she can press ALT+H and the Form will be shown using ShowDialog() and when it's done, the user will close the FormHelper, and the same process will happen for as many times the FormHelper is required.
The reason why I want the same Form to open multiple times, is that the user is filling certain values in it and I want to persist the values the next time the FormHelper is shown again and when the user is done completely with the FormMain, the values in the FormMain will be saved along with the values in FormHelper.So when the user presses ALT+H each time, the following code will not work:
BillsForm= new FormHelper();
BillsForm.ShowDialog();
as it is creating a new form and all the old values will be deleted.
In your main form, store a reference to the helper form.
You instantiate the helper form once (onLoad for example) and keep calling showDialog() on that same object. All the fields should be retained between calls.
If you were to store those values in the main form after closing, you could send those values back to the FormHelper upon creation either through the constructor or setters. From your question it already sounds like you're going to be storing those values that you want to persist inside the main form, so setting them upon creation shouldn't be an issue.
How would one switch a public bool to true from a child form in a mdi type program?
I have a child form called logon that if everything checks out i want to set a "authenticated" bool to true in the form1 (main) form
The proper, true OO way of doing things would be to expose an event on your child form that the parent can attach to. You're violating your separation of concerns if you have the child form make assumptions about its MdiParent.
For example, a very simple method of doing what you describe would be to have this on your child form:
public event EventHandler Authenticated;
The when the parent opens it...
YourForm newForm = new YourForm();
newForm.Authenticated += new EventHandler(newForm_Authenticated);
newForm.MdiParent = this;
// and so on
You could also go slightly more sophisticated (and I do mean slightly) by adding an Authenticated boolean property to your child form, and rename the event to AuthenticatedChanged. You could then use the same event handler to inspect the value of the property to determine if the user has authenticated.
In either scenario, you simply raise your event from the child form when you want the parent to update.
You could make a globally accessible variable that holds the main form, then use that variable within the child to call methods on the main form.
Or, you could cast the appropriate Parent or Owner property of the child window to the proper type of the main form, and work from there.
Since I noticed you are using a "logon" form you could try the following: set the logon form's DialogResult property according to username/password testing success. I am using username/pass just as an example.
On the logon form do something like:
if(isMatch(username, password)){
this.DialogResult=DialogResult.OK;
this.Close();
}
else MessageBox.Show("Logon error - try again!");
// or anything else you would like to do in case of an error
And then on the parent form:
LogonForm f = new LogonForm();
if(f.ShowDialog() == DialogResult.OK){
// continue
}
else {
// abort
}