I have the following situation: The main window where some of the data is completed, it is also a button that opens a new modal window where you choose the product and the range of products, I click OK and move on to the next screen where choose the quantity, price, and after approval of the data which I click OK, I want to have access to the data selected in modal windows in the main window, as it can be done using C #?
You can do something that looks more or less like this:
private void button1_Click(object sender, EventArgs e)
{
Form2 firstPopup = new Form2();
firstPopup.ShowDialog();
var someData = firstPopup.SomeValue;
Form2 secondPopup = new Form2();
secondPopup.ShowDialog();
var someOtherData = secondPopup.SomeValue;
doSomeStuff(someData, someOtherData);
}
In this case SomeValue is a property on the form with a public getter and a private setter. It's value will be set sometime before the form is closed. You can have any number of such properties per form, and any number of forms.
This is similar to the way that Open, Save As and Folder dialogs work. Take for example the Open File Dialog, once you click OK, you have access to the file that was selected
Suggestion:
In your modal window, set some public properties which hold your data. Set your OK button to set the forms DialogResult to OK, in your parent form you can do the following test (in this instance, DataModel is the data you are trying to access)
if(modalWindow.DialogResult == DialogResult.OK)
{
this.DataModel = modalWindow.DataModel;
}
Here is some information on how to use DialogResult
http://msdn.microsoft.com/en-us/library/system.windows.forms.form.dialogresult.aspx
Typically with a Modal window you follow a similar pattern to that used by the OpenFileDialog, where you do something like this:
public class MyDialog : Form
{
public MyResult Result { get { /* code elided */ } }
}
I.e, in addition to having the modal form's code - you also expose a public Result property of a given type which can provide the data entered on that form's UI (this is better than exposing the controls on the form as it means you are free to change all of that without having to re-code any other forms that depends on it).
You make sure that the Result is guaranteed to be available and valid if the Ok or Yes (whatever the confirmation button is) button is clicked. Then you make sure that you set the DialogResult of the form accordingly (you can assign one to each button as well - e.g. DialogResult.Cancel to a cancel button).
Then when you open your form you do it something like this:
var form1 = new MyDialog();
if(form1.ShowDialog() != DialogResult.OK)
return; //abort the operation, the user cancelled/closed the first modal
MyResult form1Data = form1.Result; //get your actual data from that modal form.
//...and then on with your second modal
So you collect the data from the modal(s) as you go along, aborting if any are cancelled.
Try not using a modal window!
If you call
var dialog = new DialogWindow();
If (dialog.ShowDialog(mainWindow) == DialogResult.OK) {
use the result of the dialog window
}
the dialog window will be modal, which means that you cannot access other windows while it is open.
With the following code, both windows are accessible at the same time. The problem is, however, that the code in the main window is not paused while the dialog runs.
var dialog = new DialogWindow();
dialog.Show(mainWindow);
You cannot use the result of the dialog window here!
Therefore you need a way to communicate the completion of the dialog to the main window. I suggest creating an event in the dialog window for this purpose
public class ProductResultEventArgs : EventArgs
{
public ProductResultEventArgs(List<Product> products)
{
Products = products;
}
public List<Product> Products { get; private set; }
}
In the dialog window
public event EventHandler<ProductResultEventArgs> ProductsChosen;
private void OnProductsChosen(List<Product> products)
{
var eh = ProductsChosen;
if (eh != null) {
eh(this, new ProductResultEventArgs(products));
}
}
private BtnOk_Click(object sender, EventArgs e)
{
OnProductsChosen(somehow get the product list);
}
In the main window you can do something like this
var dialog = new DialogWindow();
dialog.ProcuctsChosen += Dialog_ProductsChosen
dialog.Show(mainWindow);
and create a handler
private Dialog_ProductsChosen(object sender, ProductResultEventArgs e)
{
use e.Products here
}
Note: Passing the main window as parameter to ShowDialog or Show makes the main window owner of the dialog. This means that the dialog window will always stay in front of the main window and cannot disappear behind it. If you minimize the main window, this will minimize the dialog window as well.
Related
Complete C# beginner here, just wondering how to open an existing form from within the current form, and close the first one. I have literally no code yet so any help is much appreciated
I had a bit of a mess around, of course not knowing anything. Something like this is about all I tried just going off of intellisense prompts:
Application.Run(Terry2);
It obviously didn't work. Here was the error
Error CS0119 'Window2' is a type, which is not valid in the given context.
I have no idea where to start so thanks in advance for the help. I am using Visual Studio 2022.
Actually there are plenty of examples for this code on the internet, first you should create both of your forms and then just create an instance of your form2 in form1 under the event of your form1's button and call it's Show() method.
private void button1_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2();
f2.ShowDialog(); // Shows Form2 you can also use f2.Show()
}
Here is a step by step explenation of the process that you should follow. I recommend you to watch some fundamental c# programming tutorials as well.
Click Here
If you've used windows for some time, you've noticed that there are two types of Dialog Boxes (forms): Modal and Modeless Dialog Boxes
Modal dialog boxes: while this one is being shown, you cannot use the other dialog boxes of the application; you'll have to finish this one before you can continue using your application. Example: File Open dialog box.
Modeless Dialog Box. A kind of dialog box that gives some extra information next to the other dialog box of your application. While this one is being shown, you can switch back to your original dialog box and enter some input.
How to show a modal dialog box
For this, you use Form.ShowDialog
In your form:
private DialogResult AskFileName()
{
using (Form myForm = new SaveFileDialog();
{
// Before showing the dialog box, set some properties:
myForm.Title = "Save file";
myForm.FileName = this.DefaultFileName;
myForm.ValidateNames = true;
...
// show the file save dialog, and wait until operator closes the dialog box
DialogResult dlgResult = myForm.ShowDialog(this);
// if here, you know the operator closed the dialog box;
return dlgResult;
}
}
private void SaveFile()
{
DialogResult dlgResult = this.AskFileName();
switch (dglResult)
{
case DialogResult.Ok:
// File is saved:
this.HandleFileSaved();
break;
case DialogResult.Cancel();
// operator pressed cancel
this.ReportFileNotSaved();
break;
...
}
}
A form is disposable, hence you should use the using statement. After creation of the form you have time to set the properties. The form is shown using ShowDialog. While this dialog box is shown, your form can't get the focus. After the operator closes the dialog box, your form gets the focus again. The return value of ShowDialog indicates the result.
If you want to save the file as a result of the operator selecting the menu item "file save", or pressing the button "Save", do the following:
private void OnMenuItemFileSave_Clicked(object sender, ...)
{
this.SaveFile();
}
private void OnButtonSave_Clicked(object sender, ...
{
this.SaveFile();
}
How to show a modeless Dialog Box
A modeless dialog box is shown using Form.Show. After you call this, your dialog box can get the focus. Therefore you'll have to remember that the form is being shown.
class MyModelessDialogBox : Form {...}
class MyForm : Form
{
private MyModelessDialogBox {get; set;} = null;
private void ShowMyModelessDialogBox()
{
if (MyModelessDialogBox != null)
{
// Dialog box already shown, TODO: report to operator?
...
return;
}
else
{
// Dialog box not shown yet; create it and show it
this.MyModelessDialogBox = new MyModelessDialogBox();
// if needed, before showing set some properties
// make sure you get notified if the dialog box is closed
this.MyModelessDialogBox.FormClosed += new FormClosedEventHandler(this.MyModelessDialogBoxClosed);
// show the dialog box:
this.MyModelessDialogBox.Show(this); // I am the owner / parent window
}
// when the modeless dialog box is closed, you get notified:
void MyModelessDialogBoxClosed(object sender, FormClosedEventArgs e)
{
// if needed, inspect e.CloseReason
// if needed, handle the DialogResult
// finally: not my form anymore. The form should disposes itself:
this.MyModelessDialogBox = null;
}
}
}
}
Before closing your form you should check if the dialog box is being shown, and close:
private void OnFormClosing(object sender, FormClosingEventArgs e)
{
if (this.MyModelessDialogBox != null)
{
// the modeless dialog box is being shown. Order it to close itself:
this.MyModelessDialogBox.Close();
// this will lead to MyModelessDialogBoxClosed
}
}
Sometimes you have a dialog box that refuses to close, for instance because the dialog box warns the operator and he clicks cancel. In that case, you should not Close the dialog box directly, but add a method to ask the dialog box nicely.
In the dialog box:
bool RequestToClose()
{
bool allowedToClose = this.AskOperatorIfCloseAllowed();
if (allowedToClose)
{
// close this dialog box.
this.Close();
// the owner of the dialog box will be notified via MyModelessDialogBoxClosed
}
return allowedToClose;
}
I have multiple form but for now only 2. A main one which gets loaded on app lunch and the other appears when the use select it from the side menu. The problem is that if the user clicks again on the menu, it creates a new form instead of keeping the same one. Something happens if they change form.
Here is the current code that handles the Click event.
private Form activeForm = null;
private void openChildForm(Form childForm)
{
if (activeForm != null)
{
activeForm.Close();
}
activeForm = childForm;
childForm.TopLevel = false;
childForm.FormBorderStyle = FormBorderStyle.None;
childForm.Dock = DockStyle.Fill;
this.panelChildForm.Controls.Add(childForm);
this.panelChildForm.Tag = childForm;
childForm.BringToFront();
childForm.Show();
}
private void btnFalderon_Terminal_Click(object sender, EventArgs e)
{
openChildForm(new FalderonTerminal());
}
So, what modification I would have to make to my code for it to understand and check if the form is already open and displays the same one, so I don't louse the information on it. Like in this case the Serial Connection being made on the "FalderonTerminal" form.
UPDATE:
So I made some changes to the condition where it look if the form is already open. But it seem's that it's alway creating a new form instead of using the old one :/
private void btnFalderon_Terminal_Click(object sender, EventArgs e)
{
if (Application.OpenForms.OfType<FalderonTerminal>().Any())
{
Application.OpenForms.OfType<FalderonTerminal>().First().BringToFront();
System.Diagnostics.Debug.WriteLine("Old Falderon Terminal");
}
else
{
System.Diagnostics.Debug.WriteLine("New Falderon Terminal");
openChildForm(new FalderonTerminal());
}
}
If the form is not null and not IsDisposed, you should be able to just show it. The problem with this code is that closing it will cause it to dispose. In that case (IsDispose || Disposing) new to create a new copy (childForm = new ChildForm()), which will start you over with a clean form.
You should be aware about the difference between a modal dialog box and a modeless dialog box. The kind of dialog box influences how you should use it in your main form.
Modal dialog box
A modal dialog box is closed before the operator can use the main form. As long as the modal dialog box is shown the user input events of the main form are not called.
The structure of usage of this is similar to the following.
Example of a file save as modal dialog box
In your main form:
public void OnMenuFileSaveAs_Clicked(object sender, ...)
{
this.FileSaveAs();
}
And FileSaveAs:
public void FileSaveAs()
{
using (SaveFileDialog dialog = new SaveFileDialog())
{
// if needed set some properties of SaveFileDialog
dialog.Title = "File Save As";
dialog.InitialDirectory = ...
dialog.AddExtension = ...
// Show the dialog and wait until the operator is finished
DialogResult dlgResult = dialog.ShowDialog(this);
switch (dlgResult)
{
case DialogResult.Ok:
// operator selected a file name
string fileName = dialog.FileName;
this.SaveFileAs(fileName);
break;
case DialogResult.Cancel:
// operator cancelled file save as
this.CancelSaveFileAs();
break;
// etc.
}
}
}
The Modal dialog box only exists during this method. As long as the modal dialog box is not closed, the main form is not accessible.
Modeless dialog box
You want to show a Modeless dialog box. While this dialog box is shown, the operator can still handle the main form. This means that your return from the event handler in the main form before the modeless dialog box is closed. Therefore you should remember the modeless dialog box.
While the modeless dialog box is not closed, everything that makes it possible to open de modeless dialog box again should be disabled.
A nice method for this, would be to disable (gray out), the buttons and the menu items that can open this dialog box. A second method would be to leave the controls enabled, and to put focus on the modeless dialog box when the control (button / menu item) is clicked.
private MyModelessDialog ModelessDialog {get; set} = null;
private bool IsModelessDialogShown => this.ModelessDialog != null;
public void OnMenuShowModelessClicked(object sender, ...)
{
// only open the modeless dialog box if not shown yet
if (!this.IsModelessDialogShown)
{
// if desired, make sure that the menu item is disabled
this.DisableMenuItemShowModeless();
this.ShowModelessDialogBox();
}
else
{
// either do nothing, or decide to give the focus to the modeless dialog box
this.SetFocusOnModelessDialogBox();
}
}
private void DisableMenuItemShowModeless()
{
this.menuItemShowModeless.Enabled = false;
// is there also a button? Disable this as well
}
private void EnableMenuItemShowModeless()
{
this.menuItemShowModeless.Enabled = true;
// is there also a button? Enable this as well
}
You can give the modeless dialog box focus by using control.Focus(). How this is done properly is out of scope of this question.
private void ShowModelessDialogBox()
{
// Create a new modeless dialog box object, and set some properties
this.ModelessDialogBox = new MyModelessDialogBox()
{
...
}
// make sure I get called when the modeless dialog box closes
this.ModelessDialogBox.Closed += this.ModelessDialogBox_Closed;
// Show the modeless dialog box as a modeless dialog box:
this.ModelessDialogBox.Show(this);
}
The modeless dialog box is shown. The operator can handle both the modeless dialog box as well as the main form. The menu item is disabled, so the operator can't click on it. If you chose not to disable it, and you click on it, no new modal dialog box is shown. The model dialog box gets the focus.
When the dialog box is closed, your main form gets notified:
private void ModelessDialogBox_Closed(object sender, EventArgs e)
{
if (Object.ReferenceEquals(sender, this.ModelessDialogBox)
{
this.ModelessDialogBox_Closed();
}
}
private void ModelessDialogBox_Closed()
{
// if needed read and process properties of the modeless DialogBox
this.ProcessModelessDialogBoxResults(this.ModelessDialogBox);
this.ModelessDialogBox -= ModelessDialogBox_Closed;
this.ModelessDialogBox.Dispose();
this.ModelessDialogBox = null;
this.EnableMenuItemShowModelesss();
}
Because I disabled the menu items that show a new modeless dialog box, Only one box will be shown. If you chose not to disable the menu item, then clicking it will set the focus on the modeless dialog box.
One last remark: did you notice that I use a lot of small procedures instead of doing everything in a few procedures. This prepares your program for changes, for instance if you decide to add a button instead of only a menu item. Of if you need to disable several menu items. Or if you decide in future versions not to disable the menu items anymore. Small procedures also make reuse and unit testing easier.
Be aware, if you close your main window while the modeless dialog box is still shown, the modeless dialog box is closed, because its Parent is closed. Everything is handled nicely, except that the operator has no chance to react on the result of the modeless dialog box. If you don't want this, subscribe your main form on IsClosing event and check IsModelessDialogBoxShown. If so, decide what to do: cancel closing? Warn the operator about the open dialog box?
I am working on a WinForms Desktop application in C# .NET. The target framework is .NET Framework 4.8. When the application is started, the main form is displayed with several buttons. Each button hides the main form when clicked and opens another form that displays data with which the user interacts. The main form is the owner of the new form.One button opens a form that presents a list of files from a network share folder in a data grid view. The user selects a row in the data grid and clicks a button to import the information in the file to various tables in a SQL Server database. When the import is complete, the selected row is removed from the data grid. When the user closes this form, there is code in the Form Closed event to show the owner. This all works well.My problem is that when the main form is unhidden, I need to disable the button that opens the form to list files to import if there are not any files in the network share folder to be imported. There is also a line of code to change the button's text property informing the user there are not any files to import.I realize I can place the code to disable the button and change button text in the VisibleChanged event. But, I only want the code to run after the owned form's closed event shows the owner form. How do I enclose the code in the main form's VisibleChanged event to disable the file import button only after the owned form is closed. Or, is it possible to edit the properties of the button on the owner form in the Form Closed event prior to the Owner.Show();I found a similar question WinForm Form Closed Event. But when I follow the suggestion
private void LoadChildForm_Click(object sender, EventArgs e)
{
ChildForm form = new ChildForm();
form.FormClosed += new FormClosedEventHandler(ChildFormClosed);
form.Show();
}
substituting my names
private void btnImportHFR_Click(object sender, EventArgs e)
{
Form form = new frmHFRFiles();
form.FormClosed += new FormClosedEventHandler(frmHFRFiles_FormClosed);
form.Show(this);
Hide();
}
Visual Studio flags frmHFRFiles_FormClosed as an error for the name does not exist in the current context.
ChildForm form = new ChildForm(this);
Then in ChildForm constructor:
MainForm m_MainForm;
Public ChildForm (MainForm mainForm)
{
m_MainForm = mainForm;
}
Then in closing event:
m_MainForm.button1.Enabled = false;
Ensure button1 is public
Here is what I did. I created a boolean variable in the main form and set the initial value to false.
private bool updateButtons = false;
The main form's constructor executes the search for files in the network folder.
public frmMainMenu()
{
InitializeComponent();
Shared.FilesForImport = GetHFRFiles();
}
The form's load event calls the EnableButtons() method
public void EnableButtons()
{
btnImportHFR.Enabled = Convert.ToBoolean(Shared.FilesForImport.Count);
btnImportHFR.Text = btnImportHFR.Enabled ? "Find Available HFR" : "No HFR For Import";
btnGetFacilityStatus.Enabled = Shared.sqlWrap.GetDataForFacStat(Shared.DsFacStat);
updateButtons = false;
}
The main form's visible changed event fires after the form load event. The network folder is not searched again because the updateButtons value is set to false.
private void frmMainMenu_VisibleChanged(object sender, EventArgs e)
{
if(updateButtons)
{
EnableButtons();
}
}
In the button click event, the updateButtons value is set to true after the main form is hidden.
private void btnImportHFR_Click(object sender, EventArgs e)
{
frmHFRFiles form = new frmHFRFiles();
form.Show(this);
Hide();
updateButtons = true;
}
The child form's closed event calls the Owner.Show() method
private void frmHFRFiles_FormClosed(object sender, FormClosedEventArgs e)
{
Owner.Show();
}
This causes the main form's visible changed event to fire. Only this time the EnableButtons() method will run because the updateButtons value is true.
private void frmMainMenu_VisibleChanged(object sender, EventArgs e)
{
if(updateButtons)
{
EnableButtons();
}
}
public void EnableButtons()
{
btnImportHFR.Enabled = Convert.ToBoolean(Shared.FilesForImport.Count);
btnImportHFR.Text = btnImportHFR.Enabled ? "Find Available HFR" : "No HFR For Import";
btnGetFacilityStatus.Enabled = Shared.sqlWrap.GetDataForFacStat(Shared.DsFacStat);
updateButtons = false;
}
Finally, the EnableButtons() method sets the updateButtons value to false.
It seems rudimentary to me, but it works. Thank you everyone for your feedback.
My problem is that when the main form is unhidden, I need to disable the button that opens the form to list files to import if there are not any files in the network share folder to be imported. There is also a line of code to change the button's text property informing the user there are not any files to import.
So your main form has a button X. If this button is clicked a method is called. This method will first hide the form, then show the subform until the subform is closed. The method should disable button X, change the button's text and unhide the form.
To make this flexible, we won't do everything in one procedure, we make several procedures with the intention of the procedure: "Inform operator there are no files to import" "Disable opening the subform", and of course their counterparts "Enable opening the subform", "Inform operator there are files to import"
TODO: invent proper method names
private void ShowNoFilesToImport()
{
this.buttonX.Text = ...;
}
private void DisableOpeningSubForm()
{
this.buttonX.Text.Enabled = false;
}
The advantage of this, is that if you later want to change the way that you want to inform the operator, for instance if you want to use an information field at the bottom of you screen, you will only have to change this in one place.
Furthermore, you can reuse the procedures, for instance you can add a menu item that will do the same as button X, this menu item can call the same methods
private void PerformActionsButtonX() // TODO: invent proper name
{
// Hide this form, and show the Subform until it is closed
this.Visible = false;
using (var dlg = new SubForm())
{
// if needed, set properties of the subForm:
dlg.Text = ...
dlg.Position = ...
// show the form until it is closed
var dlgResult = dlg.ShowDialog();
this.ProcessDlgResult(dlgResult, dlg);
}
// Show that there are no files to Import and disable OpeningSubform
this.ShowNoFilesToImport();
this.DisableOpeningSubform();
// Finally: show this form:
this.Visible = true;
}
And of course call this method when ButtonX or menu item Y are clicked:
private void OnButtonX_Clicked(object sender, ...)
{
this.PerformActionsButtonX();
}
private void OnMenyItemYClicked(object sender, ...)
{
this.PerformActionsButtonX();
}
I have an application in which I need to make sure the form opened by click on a button on a user control using ShowDialog(), will be closed and disposed when I dispose the user control.
I'm calling userControl.Dispose() in my main form through a timer.
Is there a way I can do that ?
Thanks...
Here is more details about the flow of the forms:
The MainForm of my application is creating a UserControl which has a Button. Than when the user clicks on the button of the user control, it shows a model form using ShowDialog.
Meanwhile, and after a few minutes, a timer in the main form replaces the existing user control with another instance of the user control. The main form calls the Dispose method of the previous user control, and the shows the new on.
But the problem is the modal dialog is still open on screen, blocking the main form. I want to close it, and the code placed after the ShowDialog method should not be executed.
Short answer
You can subscribe Disposed event of your UserControl and close the form which it shows. Regarding to the comments under the question, it looks like you have a UserControl containing a Button and in Click event of the button, you show a Form using ShowDialog().
To close and dispose the form, you need to subscribe Disposed event of your UserControl before showing the form as dialog.
More details
If you want to decide to run some logic depending to the dialog result of the form, you can check the dialog result and if it's OK, run the custom logic which you need.
To enhance the flow a bit, you can define some events and properties in your user control and handle them in the main form:
OKSelected event, and you can raise it immediately after closing the dialog if the dialog result is OK. It will let you to handle this event in the main form, for example to stop the timer if the user clicked OK in dialog.
ProcessingFinished, and you can raise it after you finished some processing after closing the dialog when the dialog result is OK. You can handle this in main form, for example to start the timer again.
You can define some properties in case you want to communicate some values with the main form.
Here is an example of the code in main form:
MyUserControl uc = null;
private void timer1_Tick(object sender, EventArgs e)
{
if (!(uc == null || uc.IsDisposed || uc.Disposing))
{
this.Controls.Remove(uc);
uc.Dispose();
}
uc = new MyUserControl();
this.Controls.Add(uc);
uc.OKSelected += (obj, args) => { timer1.Stop(); };
uc.ProcessingFinished += (obj, args) =>
{
MessageBox.Show(uc.Info);
timer1.Start();
};
}
And here is an example of the user control:
public partial class MyUserControl : UserControl
{
public MyUserControl() { InitializeComponent(); }
public EventHandler OKSelected;
public EventHandler ProcessingFinished;
public string Info { get; private set; }
private void button1_Click(object sender, EventArgs e)
{
using (var f = new Form()) {
var button = new Button() { Text = "OK" };
f.Controls.Add(button);
button.DialogResult = DialogResult.OK;
this.Disposed += (obj, args) => {
if (!(f.IsDisposed || f.Disposing)) {
f.Close(); f.Dispose();
}
};
if (f.ShowDialog() == DialogResult.OK) {
//If you need, raise the OKSelected event
//So you can handle it in the main form, for example to stop timer
OKSelected?.Invoke(this, EventArgs.Empty);
//
//Do whatever you need to do after user closed the dialog by OK
//
//If you need, raise the ProcessingFinished event
//So you can handle it in the main form, for example to start timer
//You can also set some properties to share information with main form
Info = "something";
ProcessingFinished?.Invoke(this, EventArgs.Empty);
}
}
}
}
Can you modify the forms that you want to close automatically? If so, try adding the following to each form:
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
if (this.Owner != null)
this.Owner.HandleDestroyed += onOwnerHandleDestroyed;
}
void onOwnerHandleDestroyed(object sender, EventArgs e)
{
this.Close();
}
NOTE: You are already using Dispose() to close the main form, so this should work. If, however, you used Close() to close the main form, then it wouldn't work because Close() doesn't close a form if it is the parent of any modal dialog.
Is possible to show "page setup" and "printer setup" as modeless forms? I used code as follows, but that forms display as modal forms:
// page setup
private void btnPageSetup_Click(object sender, EventArgs e)
{
this.pageSetupDialog1.PageSettings = new PageSettings();
this.pageSetupDialog1.PrinterSettings = this.printDocument1.PrinterSettings;
this.pageSetupDialog1.ShowDialog();
if (this.pageSetupDialog1.PageSettings != null)
{
this.printDocument1.DefaultPageSettings = this.pageSetupDialog1.PageSettings;
}
}
// print setup
private void btnPrintSetup_Click(object sender, EventArgs e)
{
this.pageSetupDialog1.Document = this.printDocument1;
if (this.pageSetupDialog1.ShowDialog() == DialogResult.OK)
{
this.printDocument1.Print();
}
}
You can show a form as non-modal by calling Show rather than ShowDialog.
However, you'll also have to shuffle your code around, because your main form will no longer sit and wait for one of the subforms to close in order to check what the user did.
For example, you'll have to change the Print Setup code such that your PageSetupDialog prints the document itself when the user clicks OK, rather than relying on the main form to act when the user has clicked OK.
Similarly, you'll need to change the Page Setup code such that your PageSetupDialog sets Document.DefaultPageSettings itself, rather than "returning" settings in the PageSettings property and relying on the main form handling them.