Why does modal-form disappear completely when minimized? - c#

I'm trying to have the owner-form minimize when the modal-form is minimized. But when I minimize the modal-form – it disappears completely. (- I can click on the owner-form.)
How do I solve this?
I have:
public partial class Form1 : Form
{
Form2 frm2 = new Form2();
public Form1()
{
InitializeComponent();
frm2.Owner = this;
}
private void button1_Click(object sender, EventArgs e)
{
frm2.ShowDialog();
}
}
And:
class Form2 : Form
{
Form1 frm1;
FormWindowState ws = new FormWindowState();
public Form2()
{
SizeChanged += new EventHandler(Form2_SizeChanged);
}
void Form2_SizeChanged(object sender, EventArgs e)
{
frm1 = (Form1)Owner;
if (WindowState == FormWindowState.Minimized)
{
ws = frm1.WindowState;
frm1.WindowState = FormWindowState.Minimized;
}
else frm1.WindowState = ws;
}
}
(While trying this, I also ran into this: Modal form doesn't appear in tray until minimized and owner-form is clicked once. How do I make it appear? )

This is by design. As part of the modality contract, showing a dialog disables all the other windows in the application. When the user minimizes the dialog window, there are no windows left that the user can access. Making the app unusable. Winforms ensures this cannot happen by automatically closing the dialog when it gets minimized.
Clearly you'll want to prevent this from happening at all. Set the MinimizeBox property to false. The MaximizeBox property ought to be set to false as well, making both buttons disappear from the window caption. Leaving room for the HelpButton btw.

I don't recall every needing this much code to get modal Windows to work. I'm concerned by your comment 'I can click on the owner form', which leads me to believe that the form is nt being correctly set up as modal. By defintion, modal forms must be dealt with before user control can return to the owner form. Minimizinfg the modal form does not constitute properly 'dealing' with the modal form.
Here is some code that I have used in the past. Notes: passing the owner as parameter in ShowDialog establishes the ownership relationship. While I suspect your code works, I've not used it that way.
Also, when I have done this, I have not put any special code in the modal form, and have also disabled all the button in the upper right corner of the form; thereby insuring that the user cannot close, minimize, or maximize the modal form outside of any buttons I have provided.
public partial class Form1 : Form
{
Form2 frm2 = new Form2();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
frm2.ShowDialog(this);
}
}
I hope this helps.

Forms have a property ShowInTaskbar. If it is set to false then the form will never appear on the task bar, even when minimized.

Add a:
Show();
At the end of Form2's event-handler.

I also had the requirement where when minimizing a dialog form it should minimize the application and when restoring the application it should show the dialog again. Here's what I did:
MainForm.cs
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2.Show(this, "Testing 123");
}
}
Form2.cs
public partial class Form2 : Form
{
bool isMinimized;
private Form2()
{
InitializeComponent();
ShowInTaskbar = false;
}
private void Form2_FormClosed(object sender, FormClosedEventArgs e)
{
if (Owner != null)
{
Owner.Enabled = true;
}
}
private void Form2_Load(object sender, EventArgs e)
{
MinimizeBox = Owner != null;
if (Owner != null)
{
Owner.Enabled = false;
}
}
private void Form2_SizeChanged(object sender, EventArgs e)
{
if (Owner != null)
{
if (WindowState == FormWindowState.Minimized && Owner.WindowState != FormWindowState.Minimized)
{
Owner.Enabled = true;
Owner.WindowState = FormWindowState.Minimized;
isMinimized = true;
}
else if (isMinimized && Owner.WindowState != FormWindowState.Minimized)
{
Owner.Enabled = false;
}
}
}
public static void Show(Form owner, string message)
{
var form2 = new Form2();
form2.label1.Text = message;
if (owner != null)
form2.Show(owner);
else
form2.ShowDialog();
}
}

Related

Hide form when minimize doesn't work in Visual C#

I'm lookin for examples how hide form when I minimize, but this.Hide() doesn't work. I don't understand what's wrong. At the moment I just want to hide Form1.
private void Form1_Resize(object sender, EventArgs e)
{
if (WindowState == FormWindowState.Minimized)
{
this.Hide();
}
}
When I click in minimize button, form goes to taskbar but form doesn't hide.
I found a solution. After InitializeComponent():
public Form1()
{
InitializeComponent();
this.Resize += SetMinimizeState;
}
Then:
private void SetMinimizeState(object sender, EventArgs e)
{
bool isMinimized = this.WindowState == FormWindowState.Minimized;
this.ShowInTaskbar = !isMinimized;
if (isMinimized)
{
// optional
notifyIcon1.ShowBalloonTip(500, "Title", "Message.", ToolTipIcon.Info);
}
}
It works!

How to have Main form's menu process events on OwnedForms?

I have a Main Form with a MenuStrip on it, and I use that MenuStrip to open new owned Forms like so:
var target = new Target();
target.Owner = this;
target.Show();
This works exactly how I want it to: the Forms are always shown in front of the Main Form.
The issue that I run into is that, when one of these owned Forms has the focus, I can't access the MenuStrip via keyboard. I'd like CTRL+S to trigger the Save functionality, the same as it does when the Main Form has the focus.
Is this possible? Is there a better way to approach this?
Sorry for the delay, but if you're still having issues or looking for a different method, see below.
In your MainForm:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ChildForm child = new ChildForm();
// KeyPreview can be set in the properties of the child form instead
child.KeyPreview = true;
child.KeyPressed += Child_KeyPressed;
child.ShowDialog();
}
private void Child_KeyPressed(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.S)
{
// Save Pressed
}
}
}
and then in your Child Form:
public partial class ChildForm : Form
{
public event EventHandler<KeyEventArgs> KeyPressed;
public ChildForm()
{
InitializeComponent();
}
private void Child1_KeyUp(object sender, KeyEventArgs e)
{
KeyPressed?.Invoke(sender, e);
}
}
Thanks to Troy Mac1ure for the direction. Here's the solution that lets me use the ShortCutKeys from the main menu.
ownedForm.KeyPreview = true;
ownedForm.KeyDown += OwnedForm_KeyDown;
private void OwnedForm_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control)
{
foreach (ToolStripMenuItem menuItem in menu.Items)
{
foreach (ToolStripMenuItem item in menuItem.DropDownItems.OfType<ToolStripMenuItem>())
{
if (item.ShortcutKeys == e.KeyData)
{
item.PerformClick();
return;
}
}
}
}
}
This doesn't handle Alt menu activation, but Paint.NET doesn't handle that either, so I view that as a nice-to-have.

how to check if a non-modal dialog is already launched

My application launches a non-modal dialog on a button click. If user clicks on that button again, I would like to do a check if that form is already running and wonder if its possible?
You can use Application.OpenForms Property
if (Application.OpenForms.OfType<YourNonModalFormType>().Any())
// one is already opened
If you want to close this form:
var form = Application.OpenForms.OfType<YourNonModalFormType>().FirstOrDefault();
if (form != null)
{
// launched
form.Close();
}
Another approach is to manually declare a variable to track your form instance:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private Form2 f2 = null;
private void button1_Click(object sender, EventArgs e)
{
if (f2 == null || f2.IsDisposed)
{
f2 = new Form2();
f2.Show();
}
else
{
f2.Close();
}
}
}

hide main form, start new form, switch between the two without closing second form

I've got two forms, with subForm being called/created by a buttonClick in Form1. Right now I can initiate subForm, hide Form1, and then unhide Form1 when subForm is closed. What I'd like to be able to do is:
If user clicks changeform button, check to see if subForm is active but hidden
If no, then initiate subForm, else hide Form1, unhide subForm and pass control to it
If user clicks subForm's changeform button, hide subForm, unhide Form1 and pass control to it
If user clicks the "X" in the upper right corner of the form, then close the application, regardless of which form is active. (Right now, selecting the "X" closes the subForm and opens/unhides Form1.)
I can find solutions that do part of the requirements (and maybe all, I'm just too noob to know). To repeat from my previous question here, the code I have so far is:
Form1
private void countClick(object sender, EventArgs e)
{
this.Hide();
subForm myNewForm = new subForm();
myNewForm.ShowDialog();
this.Show();
countSelect.Checked = false;
}
and subForm
private void totalClick(object sender, EventArgs e)
{
this.Close();
}
This works, but it's not really elegant.
I think the best way to do this is to roll your own ApplicationContext. This allows you full control over the application lifetime without having it being tied to a specific Window. See http://msdn.microsoft.com/en-us/library/ms157901.aspx for more information.
Here's an example:
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyApplicationContext());
}
}
public class MyApplicationContext : ApplicationContext
{
public MyApplicationContext()
{
ShowForm1();
}
public void ShowForm1()
{
if (_form2 != null)
_form2.Hide();
if (_form1 == null)
{
_form1 = new Form1(this);
_form1.FormClosed += OnFormClosed;
}
_form1.Show();
MainForm = _form1;
}
public void ShowForm2()
{
if (_form1 != null)
_form1.Hide();
if (_form2 == null)
{
_form2 = new Form2(this);
_form2.FormClosed += OnFormClosed;
}
_form2.Show();
MainForm = _form2;
}
private void OnFormClosed(object sender, FormClosedEventArgs e)
{
if (_form1 != null)
{
_form1.Dispose();
_form1 = null;
}
if (_form2 != null)
{
_form2.Dispose();
_form2 = null;
}
ExitThread();
}
private Form1 _form1;
private Form2 _form2;
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public Form1(MyApplicationContext context)
: this()
{
_context = context;
}
private void button1_Click(object sender, EventArgs e)
{
if (_context != null)
_context.ShowForm2();
}
private readonly MyApplicationContext _context;
}
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
public Form2(MyApplicationContext context)
: this()
{
_context = context;
}
private void button1_Click(object sender, EventArgs e)
{
if (_context != null)
_context.ShowForm1();
}
private readonly MyApplicationContext _context;
}
So we'll start out by going to the child form and creating a new event that can be used to notify the parent when it wants to change forms:
public event Action ChangeForm;
Then we fire the event and hide the child form when it wants to change forms:
private void ChangeForm_Click(object sender, EventArgs e)
{
Hide();
if (ChangeForm != null)
ChangeForm();
}
The parent form needs an instance of the child form as an instance field:
private subForm child = new subForm();
And it needs to initialize it in it's constructor, both adding handlers to the ChangeForm event to show the parent, and to the closed event to close itself:
public Form1()
{
InitializeComponent();
child.ChangeForm += () => Show();
child.FormClosed += (s, args) => Close();
}
Then all that's left is for the parent form to hide itself and show the child when it wants to change forms:
private void ChangeForm_Click(object sender, EventArgs e)
{
Hide();
child.Show();
}
Why not simply setting them to foreground, topmost, and so on ?
And setting them back vice versa ?
---added as comment as proposed
To access MainForm fromsubForm:
Create a constructor in your subForm and a field:
MainForm MainFormRef_Field;
subForm(MainForm MainFormRef)
{
this.MainFormRef_Field = MainFormRef;
}
Now you can access your MainForm using this reference. Like this:
MainFormRef_Field.Show();
MainFormRef_Field.Hide(); //or how ever you want to handle it
To access subForm fromMainForm:
To handle your subForm use the object you created for it. Here:
subForm myNewForm = new subForm();
To close whole application if any of the form closes:
Set a Form_Closing event for both forms:
private void MainForm_Closing(object sender, EventArgs e)
{
Application.Exit();
}
private void subForm_Closing(object sender, EventArgs e)
{
Application.Exit();
}
Note:
I am not writing the whole code for all of your cases. Set the variables, check the conditions. Its all up to you that how code it. All the main points you needed I've provided you the solution of them.

How can I stop a dialog window from getting hidden

If I create a class derived from System.Windows.Window and show it with ShowDialog it appears above the main window as expected, and the main window is disabled.
However it is possible to put both windows behind other applications, and then just bring the main window back. This just leaves a single window which appears to have crashed, and can be confusing.
Is it possible to ensure that the dialog window is always displayed if the main window is shown? The MessageBox.Show dialog has no such problems
Update:
A test dialog is defined as
public partial class MyDialog : Window
{
public MyDialog()
{
InitializeComponent();
}
}
and called using
MyDialog d = new MyDialog();
d.ShowDialog();
you have to set the Owner property.
MyDialog d = new MyDialog();
d.Owner = Application.Current.MainWindow;//or your owning window
d.ShowDialog();
To ensure that the dialog window is always displayed if the main window is shown, add handler to main form visibility changed event to set TopMost true or false to child form according to main visibility
ChildForm frmDLg = null;
public MainForm()
{
this.VisibleChanged += MainFrmVisibleChanged;
}
private void LoadDialogForm()
{
try {
if (frmDLg == null || frmDLg.IsDisposed) {
frmDLg = new ChildForm();
}
frmDLg.ShowDialog();
} catch (Exception ex) {
//Handle exception
}
}
private void MainFrmVisibleChanged(object sender, System.EventArgs e)
{
if (frmDLg != null && !frmDLg.IsDisposed) {
frmDLg.TopMost = this.Visible;
}
}
Update
public override bool Visible
{
get
{
return base.Text;
}
set
{
base.Text = value;
// Insert my code
if (frmDLg != null && !frmDLg.IsDisposed)
{
frmDLg.TopMost = this.Visible;
}
}
}
The last cure i can think is to use a timer with user32 dll getforegroundwindow to check if main form is visible.
This code should work as you want
public MainWindow()
{
InitializeComponent();
this.Activated += new EventHandler(MainWindow_Activated);
}
void MainWindow_Activated(object sender, EventArgs e)
{
if (m == null)
return;
m.Activate();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
m = new MyDialog();
m.ShowDialog();
}
MyDialog m;

Categories