[C#]窗体切换--避免开启多个线程
先说说这个多窗体的界面的解决的办法:
用到的方法很简单,就是程序运行就建立一个MainForm,在这个MainForm中设立一个Panel,同时设立几个按钮,按下每个按钮都在这个Panel中载入不同的窗体,这样就解决了多窗体的切换。
提示:
在Panel的子窗体可以通过设置Form的FormBorderStyle为none,去掉它的最大化最小化和关闭按钮。但是一旦设置这个属性就必须手动的调用这个窗体的close方法来关闭这个窗体,因为调用这个方法和鼠标点击窗体的x按钮是一样的效果,都会调用窗体的close函数。同时这个函数的调用也会触发窗体的formclosing等事件。
下面看一下第一次写的代码:
//MainForm的代码 public class RobotArrounding : Form { private int curSelect = 0; public RobotArrounding() { InitializeComponent(); this.pnlMain.Controls.Clear(); MonitorForm monitorFrm = new MonitorForm(); monitorFrm.TopLevel = false; monitorFrm.Dock = DockStyle.Fill; monitorFrm.Show(); this.pnlMain.Controls.Add(monitorFrm); } private void btnMonitor_Click(object sender, EventArgs e) { if (curSelect != 0) { this.pnlMain.Controls.Clear(); MonitorForm monitorFrm = new MonitorForm(); monitorFrm.TopLevel = false; monitorFrm.Dock = DockStyle.Fill; monitorFrm.Show(); this.pnlMain.Controls.Add(monitorFrm); } curSelect = 0; } private void btnPlane_Click(object sender, EventArgs e) { if (curSelect != 1) { this.pnlMain.Controls.Clear(); CheckingPlane planeFrm = new CheckingPlane(); planeFrm.TopLevel = false; planeFrm.Dock = DockStyle.Fill; planeFrm.Show(); this.pnlMain.Controls.Add(planeFrm); } curSelect = 1; } private void btnHistoryChecking_Click(object sender, EventArgs e) { if (curSelect != 2) { this.pnlMain.Controls.Clear(); HistoryChecking historyFrm = new HistoryChecking(); historyFrm.TopLevel = false; historyFrm.Dock = DockStyle.Fill; historyFrm.Show(); this.pnlMain.Controls.Add(historyFrm); } curSelect = 2; } private void bntExit_Click(object sender, EventArgs e) { this.Close(); //退出整个程序 Application.Exit(); } }
代码很简单,每次点击按钮都new一个新的窗体并显示。但是后来发现这样有问题,那就是多次按按钮,切换界面以后,原本new出来的窗体并没有销毁,没有被垃圾回收器收回。而是在整个程序退出的时候才调用了窗体的close方法,验证的方法就是在每一个窗体中增加formclosing事件,验证这个事件触发的时间,代码:
//其中的一个界面的类 public partial class CheckingPlane : Form { public CheckingPlane() { InitializeComponent(); } private void CheckingPlane_FormClosing(object sender, FormClosingEventArgs e) { int a = 0; a = 10; } }
在MainForm调用application.Exit()方法得时候,发现这个窗体类的FormClosing事件执行了好多次,这个原因就是切换好多次的窗体之后,new出来了好多的窗体的实例。
解决的办法:
如果一个窗体没有被要求显示,那么这个窗体就不用new一个实例,如果这个窗体要求显示,那么就new一个窗体的实例,然后一直保持一个窗体的单例模式,直到整个程序退出时才销毁这个窗体。
public partial class RobotArrounding : Form { private int curSelect = 0; private Form[] selectFrm = null; public RobotArrounding() { InitializeComponent(); selectFrm = new Form[3]; this.pnlMain.Controls.Clear(); selectFrm[0] = new MonitorForm(); selectFrm[0].TopLevel = false; selectFrm[0].Dock = DockStyle.Fill; selectFrm[0].Show(); this.pnlMain.Controls.Add(selectFrm[0]); } private void btnMonitor_Click(object sender, EventArgs e) { if (curSelect != 0) { this.pnlMain.Controls.Clear(); if (selectFrm[0] == null || selectFrm[0].IsDisposed) { selectFrm[0] = new MonitorForm(); selectFrm[0].TopLevel = false; selectFrm[0].Dock = DockStyle.Fill; } else { selectFrm[0].Activate(); } selectFrm[curSelect].Hide(); selectFrm[0].Show(); this.pnlMain.Controls.Add(selectFrm[0]); } curSelect = 0; } private void btnPlane_Click(object sender, EventArgs e) { if (curSelect != 1) { this.pnlMain.Controls.Clear(); if (selectFrm[1] == null || selectFrm[1].IsDisposed) { selectFrm[1] = new CheckingPlane(); selectFrm[1].TopLevel = false; selectFrm[1].Dock = DockStyle.Fill; } else { selectFrm[1].Activate(); } selectFrm[curSelect].Hide(); selectFrm[1].Show(); this.pnlMain.Controls.Add(selectFrm[1]); } curSelect = 1; } private void btnHistoryChecking_Click(object sender, EventArgs e) { if (curSelect != 2) { this.pnlMain.Controls.Clear(); if (selectFrm[2] == null || selectFrm[2].IsDisposed) { selectFrm[2] = new HistoryChecking(); selectFrm[2].TopLevel = false; selectFrm[2].Dock = DockStyle.Fill; } else { selectFrm[2].Activate(); } selectFrm[curSelect].Hide(); selectFrm[2].Show(); this.pnlMain.Controls.Add(selectFrm[2]); } curSelect = 2; } private void bntExit_Click(object sender, EventArgs e) { for (int i = 0; i < 3; i++ ) { if (selectFrm[i] != null) { selectFrm[i].Close(); } } this.Close(); Application.Exit(); } }
这样写还有一个小的问题,那就是我自己的继承自Form的窗体类,如果有自己定义的函数,利用多态访问这个窗体的时候就不能访问到这个函数。其实这个也很简单,在需要访问子类自定义的函数的时候,强制转换一下类型就可以了。
这样一来,不管你切换多少次窗体,都只有一个窗体的实例了,这样就能防止new很多的窗体实例了。