多表单应用程序显示和隐藏表单的最佳实践?

StackOverflow上有很多问题,询问如何隐藏Form1并显示Form2。 并且,通常会出现一些不同的答案:

1)

// Program.cs Application.Run(new Form1()); // Form1.cs Form2 form2 = new Form2(); form2.Show(); this.Hide(); 

2)

 // Program.cs Form1 form1 = new Form1(); Form2 form2 = new Form2(); form1.Show(); form2.Show(); Application.Run(); 

...etc..

我不是在寻找像#1这样简单的一次性解决方案。 我正在寻找最佳的表单管理实践。 一个5-8种forms的应用程序,经常打开和关闭 – 管理这些表单的最佳方法是什么?

我的想法是让每个表单成为一个(懒惰?)Singleton并将它们埋没在某种FormsManager类中(比如解决方案#2但是++)。 然后单个表单可能会调用类似FormsManager.GetForm()

但我想知道有更多经验的人使用过什么。 同样,这些解决方案不应该是快速破解。 它们应该是面向设计的 ,可能是架构的 ,也是长期的解决方案

编辑:

对于可能遇到同样问题的人来说,这是一个非常通用的问题(因此要求非常开放)。 具体到我的情况,我不需要在启动时显示多个表单。 另外,我没有MDI表格。 我可能有一些模态forms,但它们大多是非模态的。

我在这里以一般方式回答。

我认为单例模式不适合表单管理。 通常,您希望将一些上下文参数传递给表单,并且您可能希望打开同一表单的多个实例。 因此单身人士不适合IMO。

我认为表单管理应该很简单。

例如,如果你想从另一个表单中显示一个模态表单,我会写一些非常简单的东西:

 private void button1_Click(object sender, EventArgs e) { using (ModalForm1 frm = new ModalForm1(myParam)) { frm.ShowDialog(); if (frm.MyResultProperty == ...) { // Do some job here } } } 

当然,你可以编写一些接口/generics语法,以避免一些代码重复,以防你想要显示很多模态forms:

 public interface IFormResult { T Result { get; set; } } public class ModalForm1 : Form, IFormResult { public ModalForm1() { InitializeComponent(); this.Result = "My result"; } public string Result { get; set; } } private void button1_Click(object sender, EventArgs e) { string res = ShowModalForm(); } private static T2 ShowModalForm() where T1 : Form, IFormResult, new() { using (T1 form = new T1()) { form.ShowDialog(); return form.Result; } } 

但说实话,我觉得它有点过分了。

第二点:如果您的表单不完全遵循此特定行为( ShowDialog()然后设置Result属性),那么您必须编写另一个接口…等。

如果这种类型的语法(generics,接口等)不减少编写的代码行数或复杂性或可维护性(显然我们不能说这是真的如此),那么它很漂亮没用的IMO。


编辑:

表单管理实际上取决于您的用例。

  • 如果您说有20个表单可以同时显示,那么您应该考虑一个FormManager概念(或者更好:考虑如何通过减少可能打开的表单的数量来改善用户体验)
  • 如果你有一些相对简单的东西(同时2-3个无模式forms+ 3-4种可能的模态forms),我不会编写复杂的代码来管理这些forms。

通常,用于启动应用程序的表单(即关闭时停止程序的表单,即作为Application.Run()参数的表单)负责其他表单。 您有一个主要表单,并且多个子表单 。 如果你的情况确实不同,那么写作可能更聪明,但这取决于你的情况。 我不认为可以为表格管理的一般问题提供一般的好答案。

老实说,如果你想要一些真正可维护的东西,尽量减少(尽可能多)可以同时显示的表格数量。 在大多数情况下,多个显示的无模式窗体不能提供良好的用户体验,并且如果窗体彼此依赖,则窗体寿命管理可能是有问题的。

除了最直接的场景之外的任何事情 – 在应用程序的生命周期中运行的单个主窗体,使用短期子窗体 – 建议创建一个inheritance自ApplicationContext的类。 它并不复杂:

 class FormManager : ApplicationContext { //When each form closes, close the application if no other open forms private void onFormClosed(object sender, EventArgs e) { if (Application.OpenForms.Count == 0) { ExitThread(); } } //Any form which might be the last open form in the application should be created with this public T CreateForm() where T : Form, new() { var ret = new T(); ret.FormClosed += onFormClosed; return ret; } //I'm using Lazy here, because an exception is thrown if any Forms have been //created before calling Application.SetCompatibleTextRenderingDefault(false) //in the Program class private static Lazy _current = new Lazy(); public static FormManager Current => _current.Value; //Startup forms should be created and shown in the constructor public FormManager() { var f1 = CreateForm(); f1.Show(); var f2 = CreateForm(); f2.ShowDialog(); } } 

Program.cs Application.RunApplication.Run可以使用FormManager的静态实例:

 static class Program { ///  /// The main entry point for the application. ///  [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(FormManager.Current); } } 

在应用程序的生命周期中,应该通过CreateForm创建新表单,以便使用FormClosed事件注册onFormClosed方法:

 var f3 = FormManager.Current.CreateForm(); f3.Show(); var f4 = FormManager.Current.CreateForm(); f4.ShowDialog(); 

如果您更喜欢new Form3(); 通过调用FormManager.CreateForm ,您可以在FormManager上创建一个RegisterForm方法:

 public void RegisterForm(Form frm) { frm.FormClosed += onFormClosed; } 

并在每个新Form上调用RegisterForm

 var f3 = new Form3(); FormManager.Current.RegisterForm(f3); var f4 = new Form4(); FormManager.Current.RegisterForm(f4); 

(注意:如果所有表单都从某个基类inheritance,那么您可以在基类构造函数中调用它,而不是为每个新实例手动调用RegisterForm 。)


请注意, Application.OpenForms仅返回当前可见的表单。 如果只要打开隐藏的表单,应用程序就不会退出,那么FormManager必须使用一些集合来跟踪所有表单。 该集合将决定是否退出该应用程序。

 class FormManager : ApplicationContext { private List
forms = new List
(); private void onFormClosed(object sender, EventArgs e) { forms.Remove((Form)sender); if (!forms.Any()) { ExitThread(); } } public void RegisterForm(Form frm) { frm.FormClosed += onFormClosed; forms.Add(frm); } public T CreateForm() where T : Form, new() { var ret = new T(); RegisterForm(ret); return ret; } private static Lazy _current = new Lazy(); public static FormManager Current => _current.Value; }

我用这个技巧,让我说form1是主要forms:

 private void button1_Click(object sender, EventArgs e) { LoadForm(new Form2()); } private void LoadForm(Form frm) { frm.FormClosed += new FormClosedEventHandler(frm_FormClosed); this.Hide(); // Here you can set a bunch of properties, apply skins, save logs... // before you show any form frm.Show(); } void frm_FormClosed(object sender, FormClosedEventArgs e) { this.Show(); } 

因此,当您关闭任何表单(form1除外)时,form1将再次出现

更新

 using (Form2 frm = new Form2()) { if (frm.ShowDialog() = DialogResult.ok) { //Do some things... } } 

在这种情况下,无需隐藏以前的表格

根据您的应用程序的大小,Id说看一下Microsoft Enterprise库,特别是CAB块。

这应该会给你一个良好的开端。

 public partial class Form1 : Form { private static Form1 inst; public static Form1 GetForm { get { if (inst == null || inst.IsDisposed) { inst = new Form1(); } return inst; } } public Form1() { InitializeComponent(); inst = this; } private void button1_Click(object sender, EventArgs e) { Form2.GetForm.Show(); this.Hide(); } } 

 public partial class Form2 : Form { private static Form2 inst; public static Form2 GetForm { get { if (inst == null || inst.IsDisposed) inst = new Form2(); return inst; } } public Form2() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { Form1.GetForm.Show(); this.Hide(); } private void Form2_FormClosed(object sender, FormClosedEventArgs e) { Form1.GetForm.Show(); } } 

如果您有两个以上的表单,则创建另一个表单作为From2