开发者

How to avoid duplicate form creation in .NET Windows Forms?

I开发者_开发百科 am using .NET Windows Forms. My MDI parent form contains the menu. If click the menu the form will be displayed. Up to now no problem.

UserForm uf = new UserForm();
uf.Show();
uf.MdiParent = this;

If I click the menu again another duplicate of the form is created. How to solve this issue?


The cleanest way is to simply track the lifetime of the form instance. Do so by subscribing the FormClosed event. For example:

    private UserForm userFormInstance;

    private void showUserForm_Click(object sender, EventArgs e) {
        if (userFormInstance != null) {
            userFormInstance.WindowState = FormWindowState.Normal;
            userFormInstance.Focus();
        }
        else {
            userFormInstance = new UserForm();
            userFormInstance.MdiParent = this;
            userFormInstance.FormClosed += (o, ea) => userFormInstance = null;
            userFormInstance.Show();
        }
    }


You should create a singleton class for managing your form instances:

public class FormProvider
{
   public static UserForm UserForm
   {
       get
       {
          if (_userForm== null || _userForm.IsDisposed)
          {
            _userForm= new UserForm ();
          }
          return _userForm;
       }
   }
   private static UserForm _userForm;
}

NB, this is a very simple Singleton pattern. For the correct way to use the pattern, use this link.

You can then just access the form as follows:

FormProvider.UserForm.Show();
FormProvider.UserForm.MdiParent = this;

When FormProvider.UserForm is accessed for the FIRST time, it will be created. Any subsequent get on the FormProvider.UserForm property will return the form that was created on first access. This means that the form will only ever be created once.


In contrast to the existing answers here, I would not recommend using a Singleton for this. The Singleton pattern is woefully overused, and is generally a "code smell" that indicates that something's gone wrong with your overall design. Singletons are generally put in the same "bucket" as global variables: you'd better have a really strong case for using it.

The simplest solution is to make an instance variable on your main form that represents the form in question, then use that to show it.

public class MainMdiForm : Form
{
    ...

    UserForm userForm;

    ...

    private void ShowUserForm()
    {
        if(userForm == null || userForm.IsDisposed)
        {
            userForm = new UserForm();
            userForm.MdiParent = this;
        }

        userForm.Show();
        userForm.BringToFront();
    }
}


If you know the name of the form :

    if (Application.OpenForms["FormName"] == null)
       {
           Form form = new Form();
           form.MdiParent = this;
           form.Show();
       }
       else
           Application.OpenForms["FormName"].Focus(); 


Options:

  • make UserForm a singleton: http://msdn.microsoft.com/en-us/library/ff650316.aspx
  • disable the button or menu item when it is clicked: menuItem.Enabled = false;

Typically, disabling the button works fine, and makes more sense from the user's perspective. Singleton works if you need the button enabled for something else.

Singleton is probably not a good solution if the form could be closed and a new instance will later be required.


You could always make the Form a Singleton:

public class MyForm : Form
{
    private MyForm _instance = null;
    private object _lock = new object();

    private MyForm() { }


    public static MyForm Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (_lock)
                {
                    if (_instance == null)
                    _instance = new MyForm();
                }
            }
            return _instance;
        }
    }
}

Then your call would look something like:

MyForm.Instance.Show();
MyForm.Instance.MdiParent = this;


You could just examine the MdiChildren property of your host form to determine if an instance of your UserForm exists in it.

UserForm myForm = null;
foreach (Form existingForm in this.MdiChildren)
{
    myForm = existingForm as UserForm;
    if (myForm != null)
        break;
}

if (myForm == null)
{
    myForm = new UserForm();
    myForm.MdiParent = this;

    myForm.Show();
}
else
    myForm.Activate();

This will create a new instance of your UserForm is it doesn't already exist, and it will switch to the created instance if it does exist.


This is my solution in ShowForm() and calling sample in aboutToolStripMenuItem_Click():

    private void ShowForm(Type typeofForm, string sCaption)
    {
        Form fOpen = GetOpenForm(typeofForm);
        Form fNew = fOpen;
        if (fNew == null)
            fNew = (Form)CreateNewInstanceOfType(typeofForm);
        else
            if (fNew.IsDisposed)
                fNew = (Form)CreateNewInstanceOfType(typeofForm);

        if (fOpen == null)
        {
            fNew.Text = sCaption;
            fNew.ControlBox = true;
            fNew.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
            fNew.MaximizeBox = false;
            fNew.MinimizeBox = false;
            // for MdiParent
            //if (f1.MdiParent == null)
            //    f1.MdiParent = CProject.mFMain;
            fNew.StartPosition = FormStartPosition.Manual;
            fNew.Left = 0;
            fNew.Top = 0;
            ShowMsg("Ready");
        }
        fNew.Show();
        fNew.Focus();
    }
    private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
    {
        ShowForm(typeof(FAboutBox), "About");
    }

    private Form GetOpenForm(Type typeofForm)
    {
        FormCollection fc = Application.OpenForms;
        foreach (Form f1 in fc)
            if (f1.GetType() == typeofForm)
                return f1;

        return null;
    }
    private object CreateNewInstanceOfType(Type typeofAny)
    {
        return Activator.CreateInstance(typeofAny);
    }

    public void ShowMsg(string sMsg)
    {
        lblStatus.Text = sMsg;
        if (lblStatus.ForeColor != SystemColors.ControlText)
            lblStatus.ForeColor = SystemColors.ControlText;
    }
    public void ShowError(string sMsg)
    {
        lblStatus.Text = sMsg;
        if (lblStatus.ForeColor != Color.Red)
            lblStatus.ForeColor = Color.Red;
    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜