After child form is hidden parent is not activated [closed] - c#

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I have 3 form: A, B, C
Form1 A;
Form2 B, C;
A is parent of B and C
public partial class Form1 : Form
{
Form2 formB = null;
Form2 formC = null;
public Form1()
{
InitializeComponent();
formB = new Form2();
formB.Owner = this;
formC = new Form2();
formC.Owner = this;
}
private void showBC_Click(object sender, EventArgs e)
{
formB.Visible = true;
formC.Visible = true;
}
}
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void hide_Click(object sender, EventArgs e)
{
this.Hide();
}
}
When application start, form A is show.
I open another program (ex: cmd), to active cmd window
I click on form A, to active form A
I click on button ShowBC -> showBC_Click
Form B and C is shown
I click button hide on C then B is actived
I click button hide on B and I hope A is active (you think so?)
cmd window is active
// ==============================================
#Sinatr
I have same problem with only A and B form
public partial class Form1 : Form
{
Form2 formB = null;
public Form1()
{
InitializeComponent();
formB = new Form2();
formB.Owner = this;
}
private void showB_Click(object sender, EventArgs e)
{
formB.Visible = true;
}
}
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void hide_Click(object sender, EventArgs e)
{
this.Hide();
}
private void MsgBox_Click(object sender, EventArgs e)
{
MessageBox.Show("Test");
}
}
When application start, form A is show.
I open another program (ex: cmd), to active cmd window
I click on form A, to active form A
I click on button ShowB -> showB_Click
Form B is shown
I click button MsgBox on form B
MessageBox "Test" is shown
I click button OK on MessageBox
Messagebox is closed
I click button hide on B and I hope A is active (you think so?)
cmd window is active
I expect A is active in the final step
Solution:
Because some child window is not form, like SelectColor Dialog, .. so I need to use win32 api to list child window to active them.
In every child form I need to do that:
[DllImport("user32.dll")]
private static extern IntPtr GetTopWindow(IntPtr parentHandle);
private static uint GW_HWNDNEXT = 2;
[DllImport("user32.dll")]
private static extern IntPtr GetWindow(IntPtr hWnd, uint wCmd);
[DllImport("user32.dll")]
private static extern int IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern IntPtr SetFocus(IntPtr parentHandle);
[DllImport("user32.dll")]
private static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
public static void SetAppFocus()
{
IntPtr topWindowHandle = GetTopWindow(IntPtr.Zero);
while (topWindowHandle != null)
{
if (IsWindowVisible(topWindowHandle) != 0)
{
int currentProcessId = Process.GetCurrentProcess().Id;
int processId = 0;
GetWindowThreadProcessId(topWindowHandle, out processId);
if (processId == currentProcessId)
{
SetFocus(topWindowHandle);
break;
}
}
// goto next window
topWindowHandle = GetWindow(topWindowHandle, GW_HWNDNEXT);
}
}

I was able to reproduce the issue.
It should be something related to activating Owner when more than one forms has same owner, because it works correctly with just one Form2.
Bug here is that another Form2 is activated if either one is closed.
Try to
void showBC_Click(object sender, EventArgs e)
{
B.Visible = C.Visible = true;
Activate();
}
Now everything work "properly": closing either Form2 will activate the owner.
If you want to keep original behavior, then here is a workaround:
public Form1()
{
InitializeComponent();
formB = new Form2 { Owner = this };
formC = new Form2 { Owner = this };
formB.VisibleChanged += Child_VisibleChanged;
formC.VisibleChanged += Child_VisibleChanged;
}
void Child_VisibleChanged(object sender, EventArgs e)
{
if (!Application.OpenForms.Cast<Form>().OfType<Form2>().Any(o => o.Visible))
Activate();
}

You are leaving it up the OS to figure out which window should be activated when the one with the focus disappears. What it does here certainly doesn't win any prizes. Also a pretty big problem with WPF dialogs btw. Exactly why it does this is hard to guess, it just doesn't seem to pay enough attention to the window owner. Do note that it works just fine when you minimize the window instead of hiding it, why that acts differently is, well, weird. Let's not hesitate calling it a bug.
The workaround is pretty straight-forward, just don't force it to find another window by itself:
if (this.Owner != null) this.Owner.Activate();
this.Hide();
Also the solution in a WPF app.

Related

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.

General buttons

I'm developing an app and I want to include some global functionality like a couple of buttons that work for every Form that the app contains.
It is a MDI application which contains four child form, each form performs different tasks and each one has its own controls. I have a Clear and Search button on each form and what I'm trying to do is to create two global buttons that perform those actions for the form that is active at the moment.
For example, Form1 is the MDI parent and Form2 is a child of Form1. I call Form2 from a ToolStripMenuItem that is in Form1, I have a button in Form2 which clear all the textboxes in it. What I want to achieve is to move the code in this button to a button placed in a general bar in Form1 (MDI parent), in order to clear not only the textboxes for Form2 but for all the forms I have in my app.
This is what I've got so far:
//Form1 code
public partial class FrmPrincipal : Form
{
public FrmPrincipal()
{
InitializeComponent();
}
private void manageUsersToolStripMenuItem_Click(object sender, EventArgs e) //Calling Form2
{
FrmUserManager frmusers = new FrmUserManager();
frmusers.MdiParent = this;
frmusers.Show();
}
}
//Form2 code
public partial class FrmUserManager : Form
{
public FrmUserManager()
{
InitializeComponent();
}
}
private void BtnClear_Click(object sender, EventArgs e)
{
Clear(this);
}
private void Clear(Control all)
{
foreach (Control all in all.Controls)
{
if (all is TextBox) ((TextBox)all).Text = string.Empty;
if (all is CheckBox) ((CheckBox)all).Checked = false;
if (all is DataGridView) ((DataGridView)all).DataSource = null;
if (all.Controls.Count > 0) Clear(all);
}
}
So, basically what I want is to move this code to a button in Form1 to perform this action from outside Form2. If I can do it, I'll be able to get rid of the buttons I have in the four child forms (Search and Clear), and besides the app will be easier to use.
The only way I've thought of is to change the property "Modifiers" on each control in Form2 to "public" to try to access them from Form1 doing something like:
Form2 frm2 = new Form2();
if(frm2.Active == true) Clear(this);
In this case, I'd instantiate each form and verified if it's active.
It does not show up any error, but still it doesn't work. I guess I know why, the object created to call Form2 is a whole different object from the one created here, so the Form2 that is currently showing is not the same that it's been referenced here.
Does anyone understand what I'm trying to do?
Why don't you set your Clear function in Form2 public, then just do:
if(frm2.Active == true) frm2.Clear(frm2);
Or, if you want this for any of the forms, clearing the active one, you just move the Clear function to Form1, then do something like:
if(this.ActiveMDIChild != null)
Clear(this.ActiveMDIChild);
You have to keep track of your child forms when you create it. You may want to do something like this :
// In the MDI form
List<Form> mChildForms = new List<Form>();
void ToolStripButton_Click(object sender, EventArgs args)
{
Form myForm = new FrmUserManager();
...
mChildForms.Add(myForm);
}
void BtnClear_Click(object sender, EventArgs args)
{
foreach (Form f in mChildForms)
if (f.Active)
Clear(f);
}
May not be accurate, I do not have Visual Studio right now.
These are steps which I did to solve this problem.
1. Create class that inherits from Form and have public ClearData() method.
public class ClearableForm : Form
{
public void ClearData()
{
Action<Control> traverseControls = null;
traverseControls = (c) =>
{
if (c is TextBox) ((TextBox)c).Text = string.Empty;
if (c is CheckBox) ((CheckBox)c).Checked = false;
if (c is DataGridView) ((DataGridView)c).DataSource = null;
c.Controls.Cast<Control>().ToList<Control>().ForEach(traverseControls);
};
traverseControls(this);
}
}
2. Make your FrmUserManager so it inherits from ClearableForm.
public partial class FrmUserManager : ClearableForm
{
public FrmUserManager()
{
InitializeComponent();
}
}
3. Add "Clear" ToolStripMenuItem to the MenuStrip on your FrmPrincipal form with the following code.
private void clearToolStripMenuItem_Click(object sender, EventArgs e)
{
foreach (Form mdi_child in this.MdiChildren)
{
if (mdi_child is ClearableForm)
mdi_child.ClearData();
}
}
I hope it solves your problem. Cheers mate!

Can not Focus() onto a Form?

I tried:
Form myForm = new EULA();
myForm.Show();
this.WindowState = FormWindowState.Minimized;
myForm.BringToFront();
myForm.Activate();
myForm.Focus();
This code brings it to the front, but for some reason I still have to click on the Form for it to have focus, can anyone tell me why?
The form may be focused already, perhaps you want a control inside it (like a textbox or a combo) to be selected instead?
I'll use this code at the form's load method:
private void Form_Load(object sender, System.EventArgs e)
{
controlName.Select();
}
Hi leaf68 just follow my codes. try to figure it out :)
Let say we have MainForm and LoginForm
In our project we have a Static Class we called Program -> The main entry point for the application. as default class to run our projects.
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new LoginForm());
if (LoginForm._loginSuccess)
{
var m = new MainForm();
Application.Run(m);
}
else
Application.Exit();
}
public static bool UserLogin() //Add some parameter
{
//You Logic here
LoginForm._loginSuccess = true;
return LoginForm._loginSuccess;
}
}
then this is our LoginForm codes
public partial class LoginForm : Form
{
public LoginForm()
{
InitializeComponent();
}
public static bool _loginSuccess { get; set; }
public event EventHandler Login;
private void loginButton_Click(object sender, EventArgs e)
{
if (Program.UserLogin())
{
Close();
Dispose();
if (Application.OpenForms.Count > 0)
if (Application.OpenForms["MainForm"].Name == "MainForm")
{
Application.OpenForms["MainForm"].WindowState = FormWindowState.Normal;
Application.OpenForms["MainForm"].Enabled = true;
}
if (Login != null)
Login(this, EventArgs.Empty);
}
}
}
then assuming that we successfully Login To MainForm so this is our MainForm codes
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void logOutButton_Click(object sender, EventArgs e)
{
//Hide();
Enabled = false;
WindowState = FormWindowState.Minimized;
var f = new LoginForm();
f.Login += loginShow;
f.Show();
f.Activate();
}
private void loginShow(object sender, EventArgs args)
{
Show();
}
}
I hope it helps you :)
I have a form not visible, so only the tray icon.
I just use:
this.ShowInTaskbar = true;
this.WindowState = FormWindowState.Normal;
this.Activate();
In the above order. Program comes to the front and is activated, meaning typing actually writes in the active field.
This works:
when program appears automatically and
when user selects tray menu item.

Why does modal-form disappear completely when minimized?

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

I would like to control Form1 from Form2

So I want basically the user to login in first in order to use the other form. However, my dilemma is that the login box is in Form2, and the main form is Form1.
if ((struseremail.Equals(username)) && (strpasswd.Equals(password)))
{
MessageBox.Show("Logged in");
form1.Visible = true;
form1.WindowState = FormWindowState.Maximized;
}
else
{
MessageBox.Show("Wow, how did you screw this one up?");
}
However, Form1 doesn't become visible, (since I launch it as visble = false) after they log in. Can someone help?
EDIT:
Brilliant response, but my problem is still here. I basically want to load Form2 First, (which is easy I run Form1 and set it to hide) But when Form2 is closed, I want Form1 to be closed as well.
private void Form2_FormClosing(Object sender, FormClosingEventArgs e)
{
Form1 form1 = new Form1();
form1.Close();
MessageBox.Show("Closing");
}
this doesn't seem to work...
You will need to pass the reference of one form to another, so that it can be used in the other form. Here I've given an example of how two different forms can communicate with each other. This example modifies the text of a Label in one form from another form.
Download Link for Sample Project
//Your Form1
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2(this);
frm.Show();
}
public string LabelText
{
get { return Lbl.Text; }
set { Lbl.Text = value; }
}
}
//Your Form2
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private Form1 mainForm = null;
public Form2(Form callingForm)
{
mainForm = callingForm as Form1;
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
this.mainForm.LabelText = txtMessage.Text;
}
//Added later, closing Form1 when Form2 is closed.
private void Form2_FormClosed(object sender, FormClosedEventArgs e)
{
mainForm.Close();
}
}
(source: ruchitsurati.net)
(source: ruchitsurati.net)
When you log in and do Form1.visible = true; have you also tried Form1.Show(); that should show form2
However, Personally, I would prefer setting the application to run form2 directly in the program.cs file.
static void Main()
{
Application.Run(new Form2());
}
then when user successfully logs in, do
form1.Show();
this.Hide(); // this part is up to you
mind you, in form2, when / after you instantiate form1, you might want to also add this :
newform1.FormClosed += delegate(System.Object o, FormClosedEventArgs earg)
{ this.Close(); };
this closes form2 when form1 is closed
better yet do form1.Show() in a new thread, and then this.Close(); for form2. this removes the need of adding to the form2's FormClosed event: you can thus close form2 immediately after starting form1 in a new thread. But working with threads might get a little complicated.
EDIT:
form2 is form1's parent. if form2 is your main application form, closing it closes your program (generally). Thus you either want to just hide and disable form2, and close it only after form1 is closed, or start form1 in a new thread. Your edit pretty much opens form1, then immediately closes it.

Categories