MDI Child Once Only please  
Author Message
Scott McKeown





PostPosted: Visual C# Express Edition, MDI Child Once Only please Top

Good Afternoon All, or morning or whatever,

I'm sure one or two of you have come accros this and the answer is probably staring me right in the face, but how do I get the child forms to be shown once, for example....

.... I have my MDI Form, a menu etc under one of my menu items "&Help" I have, "&About", "&Support" and "&Licence" now I only what each of these forms to be shown once.

I have tried:
about f = new about();

f.MdiParent = this;

f.ShowDialog();

but this just throughts an exception (cant remember of the top of my head) some thing like this form can not be displayed in this manor.

When I get home I'll make a note of the error and post it here (if I remember).

Thanks

Scott




Visual Studio Express Editions14  
 
 
Scott McKeown





PostPosted: Visual C# Express Edition, MDI Child Once Only please Top

Hi everyone,

Here is a screen shot of the error I'm getting when I use the ShowDialog to try and make a child form desplay once only.

http://aspspider.biz/redit/errors/showdialog_error01.png

Thanks

Scott



 
 
Yogesh Prabhu





PostPosted: Visual C# Express Edition, MDI Child Once Only please Top

When you want to show the forms modally by using ShowDialog() method, you don't need to assign MDI Parent to them. Simply comment the line "f.MdiParent = this;" from your code, and it should work just fine.
 
 
Scott McKeown





PostPosted: Visual C# Express Edition, MDI Child Once Only please Top

Hi Yogesh Prabhu,

Thanks for the reply, but that does not solve the problem.

This would create the child from outside of the MDI Pain, which I don't want, I still need the child form to be contained within its parent, have the normal min,max close and to show in the windows menu list. What I dont want is two copies of the same child form to be open at the same time.

Scott



 
 
Blair Allen Stark





PostPosted: Visual C# Express Edition, MDI Child Once Only please Top

try this pattern . . . Use "Visual Inheritance." a baseform class has a static dictionary that keeps track of singleton instances of inherited forms and their WindowState. 

  1. Create a new Windows Forms application project - SingletonForms
  2. Add a new Windows form - BaseForm.cs
    using System;
    using
    System.Collections.Generic;
    using
    System.ComponentModel;
    using
    System.Data;
    using
    System.Drawing;
    using
    System.Text;
    using
    System.Windows.Forms;

    namespace
    SingletonForms
    {

        public
    partial class BaseForm : Form 
       
            private FormWindowState _lastState = 
                                FormWindowState.Normal;
            
           
    // This will hold instances of inherited forms
           
    private
    static Dictionary<Type, BaseForm> _instances;
            
           
    // Static constructor to assure the 
           
    // dictionary is created before use
            static
    BaseForm() 
           
                _instances =
    new Dictionary<Type, BaseForm>(); 
           
            
            
    // When an instance is created, 
           
    // store it in the dictionary 
           
    public
    BaseForm() 
           
                InitializeComponent(); 
                _instances[
    this.GetType()] = this
                this.Text = this.GetType().ToString(); 
            }
     
             
           
    // Singleton pattern, implemented for 
           
    // inheritance   
            public
    static BaseForm GetInstance(Type t ) 
           
                BaseForm result = null
                if(!_instances.TryGetValue(t, out result)) 
                result =
    Activator.CreateInstance(t) as BaseForm
                return result; 
           
             
           
    // Store the last size for window restoration 
           
    protected
    override void OnSizeChanged(System.EventArgs e ) 
           
                if (this.WindowState != FormWindowState.Minimized) 
                    _lastState =
    this.WindowState; 
                base.OnSizeChanged(e); 
           
             
           
    // Window size restoration 
           
    public
    void Restore() 
           
                this.WindowState = _lastState; 
                this.BringToFront(); 
           

            // overload on show to restore size 
           
    public
    new void Show() 
           
                base.Show(); 
                this.Restore(); 
           
             
           
    // On close remove from dictionary 
           
    protected
    override void OnClosed(System.EventArgs e ) 
           
                _instances.Remove(
    this.GetType()); 
                base.OnClosed(e); 
           
        }
    }
  3. Build the project
  4. add a new Windows form- Server1.cs, but select "Inherited form" from the templates and select BaseForm.
  5. repeat step 4, calling the file Server2.cs  
  6. Change the original form1 to an MdiContainer.
  7. Place a menu strip on the form add a top level menu entry "Servers" with child menu items - Server1 and Server2
  8. Put this code in form1.cs:
    using System;
    using
    System.Collections.Generic;
    using
    System.ComponentModel;
    using
    System.Data;
    using
    System.Drawing;
    using
    System.Text;
    using
    System.Windows.Forms;

    namespace
    SingletonForms

        public partial class Form1 : Form 
        { 

            public
    Form1() 
            { 
                InitializeComponent(); 
                server1ToolStripMenuItem.Tag = typeof(
    SingletonForms.Server1
    ); 
                server2ToolStripMenuItem.Tag =
    typeof(SingletonForms.Server2);  
                server1ToolStripMenuItem.Click += ServerItem_Click; 
                server2ToolStripMenuItem.Click += ServerItem_Click; 
            } 

            private
    void ServerItem_Click(object sender, EventArgs e) 
            { 
                ToolStripMenuItem menu = sender as ToolStripMenuItem
                if (sender == null || menu.Tag ==null) return
                BaseForm frm = BaseForm.GetInstance((Type) menu.Tag); 
                frm.MdiParent =
    this
                frm.Show(); 
            } 

        }
    }


 



 
 
Ancalagon





PostPosted: Visual C# Express Edition, MDI Child Once Only please Top

Hi, I think I was having the same problem as you only that I didn’t have a MDI form
What I wanted: to click some button (About for example) everytime I wanted but the result is one and only one instance of the Form that button calls, Exactly the same way the "Insert->Symbol" works in MSWord
look for my thread and the solution a guy gave to me. I user the second solution from the two he gave. I hope that works:

http://forums.microsoft.com/MSDN/ShowPost.aspx PostID=704364&SiteID=1

The "Insert Link" desn’t seem to work under firefox, sorry.

 
 
Yogesh Prabhu





PostPosted: Visual C# Express Edition, MDI Child Once Only please Top

Hi Scott,

Gotcha, what you need to do is before you show your child form, you need to make sure it is not already shown. You can check this by looking into MdiChildren property of the MDI form. If form is available in that collection you can simply activate it, otherwise you can create a new instance of the form and update its MdiParent property. Add following function to your MDI form:

intenal void ShowForm<T>() where T : Form, new()

{

foreach (Form form in MdiChildren)

{

if (form.GetType() == typeof(T))

{

form.Activate();

form.WindowState = FormWindowState.Normal;

}

}

T formToShow = new T();

formToShow.MdiParent = this;

formToShow.Show();

}

and in your child form menu click handlers you can make calls to this functions, e.g

ShowForm<Form1>();

ShowForm<AboutForm>();

Hope this helps, let me know if otherwise.


 
 
nobugz





PostPosted: Visual C# Express Edition, MDI Child Once Only please Top

That's a lotta code, I might be missing something. Try this from the MDI parent:

Form2 f2 = new Form2();
f2.StartPosition = FormStartPosition.CenterParent;
f2.ShowDialog(this);

If you call it from an MDI child:
f2.ShowDialog(this.MDIParent);



 
 
Scott McKeown





PostPosted: Visual C# Express Edition, MDI Child Once Only please Top

Hi Blair Allen Stark,

Thanks for this, but this is C# express edition and I dont have access to the "Inherited Form" option.

Thanks for the code though, I'll hold on to it for when I do finaly get the full version

Scott



 
 
Scott McKeown





PostPosted: Visual C# Express Edition, MDI Child Once Only please Top

Hi Yogesh Prabhu,

This code does not seem to work for me, can you just confirm that in the click even to my menu items, for example the Help option i would put under the click event handler

ShowForm<MDI>(); // this is the name of my mdi parent

ShowForm<help>(); // this is the name of my help form

this is what I'm having problems with.

Any thoughts, thanks again

Scott



 
 
Scott McKeown





PostPosted: Visual C# Express Edition, MDI Child Once Only please Top

Hi nobugz,

this is close to what I was trying myself, this does indeed only show the form once but what is the point of me having a MDI Form if I use this option

I cant open anyother windows due to the Form2 having the focuse and I'm now not able to use the menu bar.

Ideas please, thanks again.

Scott



 
 
nobugz





PostPosted: Visual C# Express Edition, MDI Child Once Only please Top

Yes, this is only applicable to forms shown as a dialog. If you want MDI child forms to be shown non-modally only once, you'll have to do a bit more work:

private Form2 mChild2;
private void toolStripButton1_Click(object sender, EventArgs e) {
if (mChild2 == null) {
mChild2 = new Form2();
mChild2.FormClosing += Child2Closing;
mChild2.MdiParent = this;
mChild2.Show();
}
mChild2.Focus();
}
private void Child2Closing(object sender, FormClosingEventArgs e) {
mChild2 = null;
}



 
 
Scott McKeown





PostPosted: Visual C# Express Edition, MDI Child Once Only please Top

Hi nobugz,

Thanks for this, I was not even close to finding this out by myself, so once again I'm in your debt.

Once again thanks

Scott



 
 
Veerendra





PostPosted: Visual C# Express Edition, MDI Child Once Only please Top

Hi Scott,

This simple logic may help you,

public partial class Form1 : Form

{

public Form1()

{

InitializeComponent();

}

bool bOpen = true;

private void aboutToolStripMenuItem_Click(object sender, EventArgs e)

{

if (bOpen)

{

frmAbout objfrmAbout = new frmAbout();

objfrmAbout.MdiParent = this;

objfrmAbout.StartPosition = FormStartPosition.CenterScreen;

objfrmAbout.FormClosed += new FormClosedEventHandler(objfrmAbout_FormClosed);

objfrmAbout.Show();

bOpen = !bOpen;

}

else

{

MessageBox.Show("Requested Form is currently open.");

}

}

void objfrmAbout_FormClosed(object sender, FormClosedEventArgs e)

{

bOpen = true;

}

}

Thanks,

Veerendra


 
 
Scott McKeown





PostPosted: Visual C# Express Edition, MDI Child Once Only please Top

Hi Veerendra,

Thats alot of code when you compare it with nobugz, thanks any how, Ill give it ago and if it works Ill mark it as such.

Scott