如何在不创建新窗体实例的情况下切换窗体?

7
在我的应用程序中,我有四个表单 form1、form2、form3 和 form4。每个表单都有两个按钮,即“下一个”和“上一个”按钮,在表单之间切换。我的问题是,如何在不创建新的表单实例的情况下在表单之间切换?以下是我的代码。
在 Form1 中:
    public Form1()
   {
       InitializeComponents();
   }

    private void Next_Click(object sender, EventArgs e)
    {
      this.Hide()
       Form2  form2 = new Form2();
       form2.Show();
    }      

在Form2中:
    public Form2()
   {
       InitializeComponents();
   }
    private void Previous_Click(object sender, EventArgs e)
    {
       this.Hide();
       Form1 form1 = new Form1();
       form1.Show();
    }

    private void Next_Click(object sender, EventArgs e)
    {
         this.Hide();
       Form3 form3 = new Form3();
       form3.Show();
    }      

在 Form3 中:
    public Form3()
   {
       InitializeComponents();
   }
    private void Previous_Click(object sender, EventArgs e)
    {
        this.Hide();
       Form2 form2 = new Form2();
       form2.Show();
    }

    private void Next_Click(object sender, EventArgs e)
    {
         this.Hide();
       Form4 form4 = new Form4();
       form4.Show();
    }      

在Form4中:
    public Form4()
   {
       InitializeComponents();
   }
    private void Previous_Click(object sender, EventArgs e)
    {
         this.Hide();
       Form3 form3 = new Form3();
       form3.Show();
    }

在主函数中:

static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        Application.Run(new Form1());


    }

在上面的代码中,我每次都创建新的表单实例,如何避免这种情况并在不创建新的表单实例的情况下在表单之间切换?请帮帮我。

2
在一个全局类中保持所有表单的公共静态变量。在form1的初始化函数中初始化form2、form3、form4。然后根据需要激活或隐藏它们即可。 - ray
如果任何答案对您有帮助,请将其标记为答案。 - Sumeshk
感谢您的建议。 - user3413736
@ray,你能否把你的答案发布为代码?这可能对我有帮助,我会更好地理解你的意思... :) - envyM6
9个回答

8

由于您是按顺序访问表单的,所以请确保使用Show方法将所有者分配给创建的表单,并在创建后将其分配给类级变量。像这样的东西应该适合您:

Form1

public partial class Form1 : Form
{
    Form2 frm2;
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (frm2 == null)
        {
            frm2 = new Form2();   //Create form if not created
            frm2.FormClosed += frm2_FormClosed;  //Add eventhandler to cleanup after form closes
         }

        frm2.Show(this);  //Show Form assigning this form as the forms owner
        Hide();
    }

    void frm2_FormClosed(object sender, FormClosedEventArgs e)
    {
        frm2 = null;  //If form is closed make sure reference is set to null
        Show();
    }
}

表单2

public partial class Form2 : Form
{
    Form3 frm3;
    public Form2()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Owner.Show();  //Show the previous form
        Hide();

    }

    private void button2_Click(object sender, EventArgs e)
    {
        if (frm3 == null)
        {
            frm3 = new Form3();
            frm3.FormClosed += frm3_FormClosed;
        }

        frm3.Show(this);
        Hide();
    }

    void frm3_FormClosed(object sender, FormClosedEventArgs e)
    {
        frm3 = null;
        Show();
    }
}

Form3

public partial class Form3 : Form
{
    public Form3()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Owner.Show();
        Hide();
    }
}

非常感谢您,您的代码建议真的很有帮助,非常感谢您。 - user3413736

4

或许有一个简单的解决方案。您可以创建一个包含所需所有表单的静态对象类。这样,您就可以从任何所选表单访问所有这些表单,而且好处是它们只会初始化一次。

public class formList
{
      private static Form1 _form1 = new Form1();
      public static Form1 form1 { get {return _form1;}
      .................
      ............
}

4

试试这个:

Form1 myForm =(Form1) Application.OpenForms["Form1"];
myForm.Show();

但这需要表单已经打开。而且通过名称引用表单我认为很丑陋。 - PMF
尽管@PMF发表了评论,但这正是我所需要的!我能找到的其他情况都只是讲述实例化一个新的窗体实例...而在我的情况下,我想要操作一个已经打开的当前窗体。 - Anthony Griggs

3

您可以检查感兴趣的表单是否存在,如果不存在,则创建它:

public static T OpenOrCreateForm<T>() 
  where T: Form, new() {

  T result;

  // Test if form exists
  foreach(Form form in Application.OpenForms) {
    result = form as T;

    if (!Object.ReferenceEquals(null, result)) {
      // Form found; and this is the right place 
      //  to restore form size,
      //  bring form to front etc.
      if (result.WindowState == FormWindowState.Minimized)
        result.WindowState = FormWindowState.Normal;

      result.BringToFront();

      return result;
    }
  }

  // Form doesn't exist, let's create it
  result = new T();
  // Probably, you want to show the created form
  result.Show();

  resturn result;
}

...
private void Previous_Click(object sender, EventArgs e)
{
   Hide();
   OpenOrCreateForm<Form1>();
 }

private void Next_Click(object sender, EventArgs e)
{
   Hide();
   OpenOrCreateForm<Form3>();
}   

1
  public bool IsFormAlreadyOpen(Type FormType)
        {
            foreach (Form OpenForm in Application.OpenForms)
            {
                if (OpenForm.GetType() == FormType)
                    return true;
            }
            return false;
        }

这个函数可以用来判断一个表单是否已经打开

调用IsFormAlreadyOpen(Form4),如果返回true则表示Form4已经打开

而在您的情况下

在每个表单的构造函数中创建下一个和上一个表单对象,并在按钮点击时调用IsFormAlreadyOpen()来判断表单是否已经打开,如果已经打开,则将该表单置于前台,否则使用obj.show()方法显示该表单,并隐藏或关闭父表单


0

在第一个表单中,只需删除this.hide()和第二个表单中的[formNameHere].show();

像这样:

表格1:

public Form1()
{
    InitializeComponents();
}

private void Next_Click(object sender, EventArgs e)
{
    this.Hide()
    Form2  form2 = new Form2();
    form2.Show();
} 

表单 2:

public Form2()
{
    InitializeComponents();
}

private void Previous_Click(object sender, EventArgs e)
{
    Form1 form1 = new Form1();
    this.Hide();
}

private void Next_Click(object sender, EventArgs e)
{
    Form3 form3 = new Form3();
    this.Hide();
}  

等等,我不太擅长解释,而且对于C#也不是很熟悉。但这应该可以运行。


0

我曾经遇到过同样的问题。我需要一个有许多表单的应用程序,并且需要在不丢失数据的情况下在表单之间前后切换。我想出了以下解决方案,并且它对我起作用了。

在主文件(Program.cs)中,编写以下两个类:

static class Variables
{
    public static DataSet Configurations = new DataSet();

    public static float ExchangeRate = 0;

    public static Dictionary<string, int> ItemsCategories = new Dictionary<string, int>();

    public static Dictionary<string, float> WeightUnits = new Dictionary<string, float>();
}

static class Forms
{
    public static Form2 F_Form2 = new Form2();

    public static Form3 F_Form3 = new Form3();
}

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    /// 
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}

第一个类用于全局变量,可以在表单之间使用。您可以通过以下方式访问任何变量:

Variables.ExchangeRate = 7.2; //(for ex).

第二个类是您定义所有表单的新实例的地方。您可以通过以下方式在所有表单中的任何位置隐藏和显示它们:
Forms.F_Form3.Show();

或者

Forms.F_Form2.Hide();

这对我来说运行得非常顺畅和完美。试试吧。


0
    //In Form1
private static Form1 i_Instance = null;
public static Form1 Instance
   {
      get
      {
        if (Form1.i_Instance == null) Form1.i_Instance = new Form1();
        return Form1.i_Instance;
      }
   }
// And instantiation in other forms shall look like following
Form1 F1 = Form1.Instance;
F1.Show();

如果我选择将Form0作为主窗体(Application.Run(new Form0()))并从该窗体打开其他窗体,则此方法有效。请注意,如果尝试从从Form0调用的任何其他窗体的实例(每个窗体只有一个实例)中进行Form0实例化尝试,则此方法将无效。在这种情况下,程序可以编译但无法运行。 - Murat TC Tokgozlu

0

看起来你想实现类似向导的功能。我建议使用单个表单,然后将自定义选项卡控件添加到其中。在表单上添加按钮以移动上一步和下一步。

要自定义选项卡控件,需要执行以下操作:

public class CustomWizard : TabControl
{
    /// <summary>
    /// This method traps windows message and hides other tabs in the tab control.
    /// Message trapped: TCM_ADJUSTRECT
    /// </summary>
    /// <param name="m">Reference to Windows message</param>
    protected override void WndProc(ref Message m)
    {
        // Second condition is to keep tab pages visible in design mode
        if (m.Msg == 0x1328 && !DesignMode)
        {
            m.Result = (IntPtr)1;
        }
        else
        {
            base.WndProc(ref m);
        }
    }

    /// <summary>
    /// This method traps the press to stop users from selecting tab page via keyboard
    /// </summary>
    /// <param name="ke">Event details</param>
    protected override void OnKeyDown(KeyEventArgs ke)
    {
        if (ke.Control && ke.KeyCode == Keys.Tab)
            return;

        base.OnKeyDown(ke);
    }

    private void InitializeComponent()
    {
        this.SuspendLayout();
        this.ResumeLayout(false);

    }
}

这个选项卡控件一次只会显示一个选项卡。虽然在设计时您可以看到它们全部。将此添加到您的表单并添加按钮。在按钮点击时,仅设置此选项卡控件的SelectedIndex属性即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接