How to forced focusing on child form? - c#

How to force fully focus child form when we click on client area of it's parent form? [Like MessageBox or Error message have such focus so we must click on Ok button of messagebox.]
This is my code:
form = new Form2();
form.MdiParent = this;
form.ShowDialog(ParentForm);
But it gives me the error:
Form that is not a top-level form cannot be displayed as a modal
dialog box. Remove the form from any parent form before calling
showDialog.

Original answer - for non-MDIChild
Make the child form modal using the ShowDialog method.
ChildForm.ShowDialog (ParentForm);
To keep an MDI Child form at the top:
Handle the MDIChildActivate event on the parent form, and in that, set the child form that you want to stay visible to be active:. In this example, Form2 is the modal form, and Form3 is another form for testing.
private Form2 frm2;
private Form3 frm3;
private void Form1_Load(object sender, EventArgs e)
{
frm2=new Form2();
frm2.MdiParent=this ;
frm2.Show();
frm3= new Form3() ;
frm3.MdiParent=this;
frm3.Show();
}
private void Form1_MdiChildActivate(object sender, EventArgs e)
{
frm2.Activate();
}

I think you want to have some kind of MessageBox in the MDI Parent Form with TopLevel = false. To make the effect look like the real effect a window shown by ShowDialog() has, I think this is the only solution which requires you to create a custom Form for your MDI child form:
public class ChildForm : Form
{
[DllImport("user32")]
private static extern int FlashWindowEx(FLASHWINFO flashInfo);
struct FLASHWINFO
{
public int cbSize;
public IntPtr hwnd;
public uint flags;
public int count;
public int timeOut;
}
protected override void WndProc(ref Message m)
{
if (ParentForm != null)
{
ChildForm dialog = ((Form1)ParentForm).Dialog;
if (dialog != this && dialog!=null)
{
if (m.Msg == 0x84) //WM_NCHITTEST
{
if (MouseButtons == MouseButtons.Left)
{
Flash(dialog.Handle);
}
return;
}
}
}
base.WndProc(ref m);
}
private void Flash(IntPtr handle)
{
FLASHWINFO flashInfo = new FLASHWINFO()
{
hwnd = handle,
count = 9,
cbSize = Marshal.SizeOf(typeof(FLASHWINFO)),
flags = 3,
timeOut = 50
};
FlashWindowEx(flashInfo);
}
public void Flash()
{
Flash(Handle);
}
//This is to disable Tab when the Dialog is shown
protected override bool ProcessTabKey(bool forward)
{
if(((Form1)ParentForm).Dialog == this) return true;
return base.ProcessTabKey(forward);
}
}
//Here is your MDI parent form
public class Form1 : Form {
public Form1(){
InitializeComponent();
IsMdiContainer = true;
f1 = new ChildForm();
f2 = new ChildForm();
f1.MdiParent = this;
f2.MdiParent = this;
//Get MDI Client
foreach(Control c in Controls){
if(c is MdiClient){
client = c;
break;
}
}
client.Click += ClientClicked;
}
ChildForm f1, f2;
MdiClient client;
public ChildForm Dialog {get;set;}
private void ClientClicked(object sender, EventArgs e){
if(Dialog != null) Dialog.Flash();
else {//Show dialog, you can show dialog in another event handler, this is for demonstrative purpose
Dialog = new ChildForm(){MdiParent = this, Visible = true};
ActivateMdiChild(Dialog);
//Suppose clicking on the Dialog client area will close the dialog
Dialog.Click += (s,ev) => {
Dialog.Close();
};
Dialog.FormClosed += (s,ev) => {
Dialog = null;
};
}
}
}

Related

How to call Parent Form method from Child Form in C#?

I have a parent form with 1 method to refresh the panel content called resetPanel() .
I also have a button in the parent form. If I click the button, a new form opens up. I will do some changes and click on save. The content gets saved in the database and the child form closes. Now the parent form will be displayed.
I want to call the resetPanel() method now, so that the panel shows the updated values.
How can I achieve this?
If your child form is a dialog one, you can just check the form's dialog result:
// Do not forget to release resources acquired:
// wrap IDisposable into using(..) {...}
using (Form myChildForm = new MyChildForm()) {
//TODO: If you want to pass something from the main form to child one: do it
// On any result save "Cancel" update the panel
if (myChildForm.ShowDialog() != DialogResult.Cancel)
resetPanel();
}
In case your child from is not a dialog you can pass this into child form as reference to main one:
Form myChildForm = new MyChildForm(this);
myChildForm.Show(); // <- Just show, not ShowDialog()
...
private MyMainForm m_MainForm;
public MyChildForm(MyMainForm form) {
m_MainForm = form;
}
private void save() {
//TODO: Save to database here
// Main form update
if (!Object.ReferenceEquals(null, m_MainForm))
m_MainForm.resetPanel(); // <- resetPanel should be public or internal method
}
private saveButton_Click(object sender, EventArgs e) {
save();
}
After you close your Form2, you can call the ResetPanel method:
Form2 f2 = new Form2();
f2.ShowDialog();
resetPanel(); // <-- this will be executed when you close the second form
for Eg ur Parent Form Name If form Form1 and child Form Name as Form2 goto ur Child form Designer page Change it Access Modifier as Public
and from what ever method you want Call
Form2 f2=new Form2();
f2.Show();
.//from here on you can write your concerned code
If your resetPanel method is doing a database call, you quite possibly can avoid it. Although this will not get any data that was being updated by another user in your application. Just modified code from another answer of mine for your needs. This is just a sample:
public class ParentForm : Form
{
Button openButton = new Button();
public ParentForm()
{
openButton.Click += openButton_Click;
}
void openButton_Click(object sender, EventArgs e)
{
ChildForm childForm = new ChildForm();
childForm.OKButtonClick += childForm_OKButtonClick;
childForm.ShowDialog();
}
void childForm_OKButtonClick(object sender, MyEventArgs e)
{
// Use properties from event args and set data in this form
}
}
public class ChildForm : Form
{
Button okButton = new Button();
TextBox name = new TextBox();
TextBox address = new TextBox();
public event EventHandler<MyEventArgs> OKButtonClick;
public ChildForm()
{
okButton.Click += okButton_Click;
}
void okButton_Click(object sender, EventArgs e)
{
try
{
bool saveSucceeded = false;
// Try saving data here
if (saveSucceeded)
{
if (OKButtonClick != null)
{
MyEventArgs myEventArgs = new MyEventArgs();
// Just get updated data from screen and send it to another form
myEventArgs.Name = name.Text;
myEventArgs.Address = address.Text;
OKButtonClick(sender, myEventArgs);
}
Close();
}
else
{
MessageBox.Show("Data could not be saved.");
}
}
catch (Exception ex)
{
// Perform proper exception handling
}
}
}
public class MyEventArgs : EventArgs
{
public string Name
{
get;
set;
}
public string Address
{
get;
set;
}
}
Try to set the Save button in your child Form to DialogResult.Ok and then make the Save button as the AcceptButton for child Form. And then test if the result if it the user press that Save Button. Programmatically it could look like this:
Form2 chidForm = new Form2();
childForm.btnSave.DialogResult = DialogResult.Ok
childForm.AcceptButton = childForm.btnSave
if (childForm.ShowDialog() == DialogResult.Ok)
{
resetPanel();
}
Now, I assume here that your Save button in Child Form is named btnSave.

How to add row in another form if running in mainForm

I've tried this code to add a row of function that I created on the main form (Form1) in DataGridView in Form2, but there is no result add row when I run its function, does anyone know where the mistake?
Thanks
[edit]Code in MainForm1 :
public partial class Form1 : Form
{
Form2 sub = new Form2();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
sub.AddRow(new string[] { "1", "2" }); // able to loop
sub.Show();
this.Enabled = false;
}
}
[edit] Code in Form2 :
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
public void AddRow(string[] values)
{
this.DGVFile.Rows.Add(values);
}
}
I get a few hints at some answers. My questions were answered when the data is loaded in datagridview in Form2 and also I want the mainform (Form1) can be disabled when opening Form2. Now it has been resolved. Thanks All.
Use sub.Show(); instead. This way, the code bellow sub.ShowDialog(); will not even get called.
ShowDialog opens a new form as a modal window, which means, that the focus is only in the new window and lines below this call are called when the new windows is closed.
You can find more information about these two methods on MSDN here and here.
UPDATE:
but i want disabled mainform if open form2
I can think of two options.
The first, and in my opinion better, is to postopne opening of the form
Form2 sub = new Form2();
sub.RegisterParent(this);
for (int x = 1; x <= 5; x++ )
{
string[] row;
row = new string[] { "1","2"};
sub.DGVFile.Rows.Add(row);
}
sub.ShowDialog(); // open when everything is prepared
The second is
sub.Show();
this.Enabled = false;
but this is not really a nice solution, because you would have to enable it from the other form before closing it and there are many ways how to close a form and you would have to consider all.
Take the creation of the second form from the button click event out: Form2 sub = new Form2();. This way the second form is created only once. Then use ShowDialog and Hide methods to show a modal second form (the first form will be inactive). Create an extra public method in the second form to add new row to the existing DataGridView.
A possible solution can look like this:
public partial class MainForm : Form
{
private DataForm dataForm = null;
public MainForm()
{
InitializeComponent();
// init data form
dataForm = new DataForm();
dataForm.Init();
}
private void buttonAddRow_Click(object sender, EventArgs e)
{
// add values
dataForm.AddRow(new string[] { "10", "20" });
// show a modal second form, so that the first can not be selected while the second is open!
dataForm.ShowDialog(this);
}
}
public partial class DataForm : Form
{
public DataForm()
{
InitializeComponent();
}
// init the grid
internal void Init()
{
this.dataGridView.Columns.Add("A", "A");
this.dataGridView.Columns.Add("B", "B");
for (int x = 1; x <= 5; x++)
{
string[] row;
row = new string[] { "1", x.ToString() };
this.dataGridView.Rows.Add(row);
}
}
// add values to the grid
public void AddRow(string[] values)
{
this.dataGridView.Rows.Add(values);
}
// hide second form
private void buttonClose_Click(object sender, EventArgs e)
{
Hide();
}
}
Output after two additions is:
The code after sub.ShowDialog(); is executed only after the form sub is closed. Try using sub.Show()
Please review the following code:
namespace TEST_CSA
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 sub = new Form2();
sub.Show(this);
this.Enabled = false;
sub.RegisterParent(this);
for (int x = 1; x <= 5; x++)
{
string[] row;
row = new string[] { "1", "2" };
sub.DGVFile.Rows.Add(row);
}
}
}
}
The command Show(this) makes Form1 the parent form of Form2 and also ensures that Form2 will be always displayed on top of Form1. To deactivate Form1 use this.Enabled = false; In order to reactivate Form1 when Form2 closes use the following code:
namespace TEST_CSA
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private Form1 _parent;
internal void RegisterParent(Form1 form)
{
this._parent = form;
}
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
_parent.Enabled = true;
}
}
}

C# Windows Forms - link instances of same Form

I'd like to create, say 32 Windows Forms based upon a single template Form, and those instances should be linked to each other. That is, every Form has a button for calling the next instance and so on. I am able to create as many forms as I like but how would I link those instances together ?
This is what I use to create several child forms:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ChildForm child = new ChildForm();
child.Show();
}
}
Sequence of events would be like:
User starts application, main form is displayed (only has "Open Child" button)
User pushes "Open child" button, first instance of child form opens
first child form (caption "Child Form 1") has button "Open Child Form 2"
if user pushes "Open Child Form 2" child form 1 is hidden and child form 2 is displayed
if the last child form is reached wrap-around to child form 1
Any ideas are welcome !
regards
Chris
You can create a static collection of the form, in the constructor add the form instance to the list (and remove it during dispose). To figure out the next form, you can find the index of the current form and grab the next form in the list based on that. Create a form with two buttons and modify it as below to test it out.
public partial class Form1 : Form
{
static List<Form1> formList = new List<Form1>();
public Form1()
{
InitializeComponent();
formList.Add(this);
}
private void button1_Click(object sender, EventArgs e)
{
int idx = formList.IndexOf(this);
int nextIdx = (idx == formList.Count()-1 ? 0: idx+1 );
Form1 nextForm = formList[nextIdx];
nextForm.changeTextAndFocus("next form: " + nextIdx);
}
// moves to the next form and changes the text
public void changeTextAndFocus(string txt)
{
this.Focus();
this.Text = txt;
}
//Creates 5 forms
private void button2_Click(object sender, EventArgs e)
{
for (int i = 0; i < 5; i++)
{
Form1 newForm = new Form1();
newForm.Show();
}
}
}
I don't really know what you are planning to do :). If you want to count several forms, you can add a property Number to the form. And searching upwards from there.
Mainform;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ChildForm first = new ChildForm();
first.Number = 1;
first.Show();
}
}
ChildForm
public partial class ChildForm : Form
{
public ChildForm()
{
// createButton here
}
private void button_Click(object sender, EventArgs e)
{
ChildForm _childForm = new ChildForm();
_childForm.Owner = this;
_childForm.Number = this.Number + 1;
this.Hide();
_childForm.Show();
}
public void FirstChildForm()
{
if (this.Number != 1) //maybe not that static
{
(this.Owner as ChildForm).FirstChildForm();
this.Close(); // or hide or whatever
}
}
public int Number
{ get; set; }
}
Not tested code, hope this helps a bit :).

How to solve this problem in Tabbed MDIChild Forms?

what is this error :
Form that was specified to be the MdiParent for this form is not an MdiContainer.
Parameter name: value
here is the code
public partial class Form5 : Form
{
public Form5()
{
InitializeComponent();
}
private void Form1_MdiChildActivate(object sender, EventArgs e)
{
if (this.ActiveMdiChild == null)
tabForms.Visible = false; // If no any child form, hide tabControl
else
{
this.ActiveMdiChild.WindowState = FormWindowState.Maximized; // Child form always maximized
// If child form is new and no has tabPage, create new tabPage
if (this.ActiveMdiChild.Tag == null)
{
// Add a tabPage to tabControl with child form caption
TabPage tp = new TabPage(this.ActiveMdiChild.Text);
tp.Tag = this.ActiveMdiChild;
tp.Parent = tabForms;
tabForms.SelectedTab = tp;
this.ActiveMdiChild.Tag = tp;
this.ActiveMdiChild.FormClosed += new FormClosedEventHandler(ActiveMdiChild_FormClosed);
}
if (!tabForms.Visible) tabForms.Visible = true;
}
}
// If child form closed, remove tabPage
private void ActiveMdiChild_FormClosed(object sender, FormClosedEventArgs e)
{
((sender as Form).Tag as TabPage).Dispose();
}
private void tabForms_SelectedIndexChanged(object sender, EventArgs e)
{
if ((tabForms.SelectedTab != null) && (tabForms.SelectedTab.Tag != null))
(tabForms.SelectedTab.Tag as Form).Select();
}
private void projectsToolStripMenuItem_Click(object sender, EventArgs e)
{
Form7 f7 = new Form7();
f7.MdiParent = this;
f7.Show();
}
}
The problem is probably that in your Form5 class you are not specifying that the Form is a MdiContainer.
Try setting the IsMdiContainer property to true or set the property manualy after you call InitializeComponent in the constructor.

Show/hide, BringToFront/SendToBack a panel on Parent form when a Child Form on the MDI Parent Form closes or appears

I need to hide a panel on the Parent Form when a Child Form on an MDI Parent Form closes & show back the panel on the Parent form when the Child Form is closed.
Currently am using SendtoBack() to show the Child Form infront of the Panel which is on the Parent Form , but when i close the Child Form, then the Panel doesn't appears back, even if i use :
BringtoFront()
OR
Panel1.Visible=true
public partial class CHILD : Form
{
private void CHILD_Load(object sender, EventArgs e)
{
this.FormClosed += new FormClosedEventHandler(CHILD_FormClosed);
}
void CHILD_FormClosed(object sender, FormClosedEventArgs e)
{
PARENTForm P = new PARENTForm();
P.panel1.BringToFront();
P.panel1.Visible = true;
}
}
public partial class Form1 : Form
{
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
CHILD P = new CHILD();
P.Showg();
P.MdiParent = this;
P.BringToFront();
panel1.SendToBack();
panel1.Visible = false;
}
}
THIS ISN'T WORKING....PLEASE HELP..!
You creating new parent form in child form. You need to pass parent form object to child form and then use it to show/hide panel and set panel Modifiers property to public.
For example...
Parent form:
public partial class ParentForm : Form
{
public ParentForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
panel1.Visible = false;
ChildForm childForm = new ChildForm();
childForm.MdiParent = this;
childForm.Show();
}
}
Child form:
public partial class ChildForm : Form
{
public ChildForm()
{
InitializeComponent();
}
private void Child_FormClosed(object sender, FormClosedEventArgs e)
{
ParentForm parentForm = (ParentForm)this.MdiParent;
parentForm.panel1.Visible = true;
}
}
Use this Code
in Parent Form
private void MainMenu_ChildForm_Click(object sender, EventArgs e)
{
ChildForm frm = new ChildForm();
frm.MdiParent = this;
ShowHideMainPanel(frm);
frm.Show();
}
void ShowHideMainPanel(Form frm)
{
frm.FormClosed += new FormClosedEventHandler(Form_Closed);
panel1.Visible = false;
}
void Form_Closed(object sender, FormClosedEventArgs e)
{
panel1.Visible = true;
}
by assigning close event for child to show panel after its closing

Categories

Resources