多表单应用程序显示和隐藏表单的最佳实践
本文关键字:表单 最佳 应用程序 显示 隐藏 | 更新日期: 2023-09-27 18:26:04
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个表单的应用程序,经常打开和关闭彼此-管理这些表单的最佳方式是什么?
我的想法是让每个表单都成为一个(懒惰的?)Singleton,并将它们埋在某种类型的FormsManager
类中(类似于解决方案#2,但++)。然后单个表单可能会调用类似FormsManager.GetForm<WelcomeDialog>()
的东西。
但我想知道有更多经验的人会用什么。同样,这些解决方案不应该是快速破解。它们应该是面向设计的,可能是architectural和长期解决方案。
编辑:
对于任何可能有同样问题的人来说,这是一个非常通用的问题(因此需求非常开放)。但具体到我的情况,我不需要在启动时显示多个表单。此外,我没有MDI表格。我可能有一些模态形式,但它们大多是非模态的。
在最简单的场景之外的任何其他场景中——一个在应用程序生命周期内运行的主窗体,带有短暂的子窗体——建议创建一个从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<T>() 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<FormManager> _current = new Lazy<FormManager>();
public static FormManager Current => _current.Value;
//Startup forms should be created and shown in the constructor
public FormManager() {
var f1 = CreateForm<Form1>();
f1.Show();
var f2 = CreateForm<Form2>();
f2.ShowDialog();
}
}
CCD_ 6中的CCD_ 5可以使用CCD_
static class Program {
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(FormManager.Current);
}
}
在应用程序的生命周期内,应通过CreateForm
创建新表单,以便使用FormClosed
事件注册onFormClosed
方法:
var f3 = FormManager.Current.CreateForm<Form3>();
f3.Show();
var f4 = FormManager.Current.CreateForm<Form4>();
f4.ShowDialog();
如果您更喜欢new Form3();
而不是对FormManager.CreateForm
的调用,则可以在FormManager
:上创建RegisterForm
方法
public void RegisterForm(Form frm) {
frm.FormClosed += onFormClosed;
}
并在每个新的CCD_ 16:上调用CCD_
var f3 = new Form3();
FormManager.Current.RegisterForm(f3);
var f4 = new Form4();
FormManager.Current.RegisterForm(f4);
(注意。如果所有表单都继承自某个基类,那么您可以在基类构造函数中调用它,而不是为每个新实例手动调用RegisterForm
。)
请注意,Application.OpenForms
只返回那些当前可见的表单。如果只要仍有隐藏的表单打开,应用程序就不应该退出,那么FormManager
将不得不使用一些集合来跟踪所有表单。该集合将决定是否退出应用程序。
class FormManager : ApplicationContext {
private List<Form> forms = new List<Form>();
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<T>() where T : Form, new() {
var ret = new T();
RegisterForm(ret);
return ret;
}
private static Lazy<FormManager> _current = new Lazy<FormManager>();
public static FormManager Current => _current.Value;
}
我在这里以一般的方式回答。
我认为单例模式不太适合表单管理。一般来说,你想把一些上下文参数传递给表单,你可能想打开同一表单的多个实例
我认为表单管理应该很简单。
例如,如果你想显示另一种形式的模态形式,我会写一些非常简单的东西:
private void button1_Click(object sender, EventArgs e)
{
using (ModalForm1 frm = new ModalForm1(myParam))
{
frm.ShowDialog();
if (frm.MyResultProperty == ...)
{
// Do some job here
}
}
}
当然,如果你想显示很多模态形式,你可以编写一些接口/泛型语法来避免一些代码重复:
public interface IFormResult<T>
{
T Result { get; set; }
}
public class ModalForm1 : Form, IFormResult<string>
{
public ModalForm1()
{
InitializeComponent();
this.Result = "My result";
}
public string Result { get; set; }
}
private void button1_Click(object sender, EventArgs e)
{
string res = ShowModalForm<ModalForm1, string>();
}
private static T2 ShowModalForm<T1, T2>()
where T1 : Form, IFormResult<T2>, new()
{
using (T1 form = new T1())
{
form.ShowDialog();
return form.Result;
}
}
但老实说,我觉得这有点过头了。
第二点:如果您的表单没有完全遵循此特定行为(ShowDialog()
,则设置了Result
属性),那么您必须编写另一个Interface。。。等
如果这种类型的语法(泛型、接口等)不能减少编写的代码行数、复杂性或可维护性(显然我们不能说这里真的是这样),那么它就毫无用处了
编辑:
表单管理实际上取决于您的用例。
- 如果你有20个可以同时显示的表单,那么你应该考虑
FormManager
的概念(或者更好:考虑如何通过减少可能打开的表单的数量来改善用户体验) - 如果你有一些相对简单的表单(同时有2-3个非模态表单+3-4个可能的模态表单),我不会写复杂的代码来管理这些表单
通常,用于启动应用程序的表单(即关闭程序时停止程序的表单,即Application.Run()
的参数表单)负责其他表单。您有一个主窗体和多个子窗体。如果你的情况真的不同,那么可能有更聪明的东西可以写,但这取决于你的情况。对于表单管理的普遍问题,我不认为有人能给出一个普遍的好答案。
老实说,如果你想要真正可维护的东西,试着(尽可能多地)减少可以同时显示的表单的数量。在大多数情况下,同时显示多个非模态表单并不能提供良好的用户体验,如果表单相互依赖,则表单生命周期管理可能会出现问题。
我使用这个技巧。假设form1是主要形式:
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();
}
因此;打开任何关闭的窗体(除窗体1外)时,窗体1将再次出现。
更新
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