第一天 -- 《2014-07-15 三层架构》2 -- 登录窗体的一般做法、多文档窗体、窗体控件的基本用法。

一、下午《04、使用SHowDIalog方式关闭登录窗体》

1、登录窗体的一般做法

<1>Main()入口方法中显示登录窗体(ShowDialog方式打开),如果登录OK,再在主窗体上做消息循环。

//入口Main方法中的主要代码:

[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    FrmLogin frm = new FrmLogin();
    //ShowDialog()方式打开 的窗体会返回一个DialogResult值
    DialogResult res = frm.ShowDialog();
    if (res == DialogResult.OK)
    {
        Application.Run(new FrmMain());
    }
}

<2>登录窗体主要代码

详见《第一天 -- 《2014-07-15 三层架构》1 -- 三层架构基本概念、一个登陆小例子》第二节第2段重构UI

简单说就是如果登录成功,登录窗体的DialogResult属性赋值OK;取消登录(以及点击右上角x关闭登录窗体)赋值Cancel。

 

 

2、“模态对话框”的注意事项

用ShowDialog()显示的窗体,为其DialogResult赋值(除DialogResult.None以外的任何值)后,窗体就会自动关闭。

例子代码如下:

 1 //主窗体点击button1,将Form2子窗体以模式对话框打开。
 2 private void button1_Click(object sender, EventArgs e)
 3 {
 4     Form f = new Form2();
 5     f.ShowDialog();
 6 
 7     //当对话框关闭后,才能接着运行下面代码。
 8     DialogResult r = f.DialogResult;
 9     MessageBox.Show("Form2对话框选择了:" + r);
10 }
11 
12 
13 
14 //Form2窗体中主要代码:
15 //创建Form2对象后,其DialogResult属性默认为None
16 private void button1_Click(object sender, EventArgs e)
17 {
18     this.DialogResult = DialogResult.OK;//赋值后会自动关闭Form2
19 }
20 
21 private void button2_Click(object sender, EventArgs e)
22 {
23     this.Close();//关闭Form2时,DialogResult属性自动设置为Cancel
24 }
25 //点击Form2右上角x关闭窗体时,DialogResult属性也是自动设置为Cancel

 

3、窗体的关闭Close与清理Dispose

<1>当主窗体关闭时,由它创建并Show的所有窗体(子窗体)都会被关闭。

<2>执行Show()方法打开的窗体被Close掉后,它(占用的资源)会被Dispose清理。但窗体对象引用并不是null,如果此时再去执行其Show()或ShowDialog(),会抛出异常:“System.ObjectDisposedException:“无法访问已释放的对象。”

<3>而执行ShowDialog()方法打开的窗体被Close掉后,它(占用的资源)不会被清理,窗体对象引用也不是null,如果此时再去执行其Show()或ShowDialog(),不会抛出异常。

<4>总结:当我们使用ShowDialog来显示窗体的时候,当你关闭的时候(不准备再打开),最好手动Dispose一下。为什么是最好呢,因为其实在GC回收垃圾的时候还是会调用窗体的Dispose的,因为在Form的基类的析构函数里面有调用Dispose(false);

   ~Component()
    {
      this.Dispose(false);
    }

其实在MSDN上微软就对这有说明,顺便吐槽一下中文MSDN的翻译,实在是太烂了。

image

在以下两种情况下调用 Close 不会清理Dispose窗体(占用的资源):
(1) 窗体是多文档界面 (MDI) 应用程序的一部分且是不可见的;
(2) 您是使用 ShowDialog 显示的该窗体。
在这些情况下,需要手动调用Dispose()来清理窗体(占用的资源)。

另外:第一种情况我测试了下,没有复现出来,MDI里面的子窗口调用Close的时候跟正常一样,每次都会自动Dispose。试了很久还是一样的结果,求高人指定吧。

引用《关于Form.Close跟Form.Dispose》

 

二、下午《05、设置MDI父子窗体》

 

1、将主窗体设置为MDI容器,子窗体的MdiParent设置为主窗体

 1 ...
 2 this.IsMdiContainer = true;//设置为多文档窗体
 3 ...
 4 
 5 private void tsmiStudent_Click(object sender, EventArgs e)
 6 {//点击按钮,打开子窗体
 7     FrmPerson frm = FrmPerson.CreateSingle();//获取单例的子窗体
 8     
 9     frm.MdiParent = this;//指定当前窗体的MDI父容器是当前窗体
10     frm.Show();
11 }

 

2、菜单栏添加窗体列表项

在菜单栏加一个菜单项(Windows),即子窗体列表。如下图所示:

 

做法:将菜单栏MenuStrip的MdiWindowListItem属性指定为某个菜单项即可。

 

 

 

三、下午《06、单例模式》--《07、另外一种方式实现窗体只能打开一次》

1、单例窗体主要代码如下:(当然单例的方式还有几种,这里不介绍了。事实上最好使用微软推荐的方式。即public static readonly 类名 Instance ......)

 1 //单例窗体FrmPerson类中
 2 ...
 3 private static FrmPerson frm = null;//单例对象
 4 
 5 public static FrmPerson CreateSingle()
 6 {
 7     //IsDisposed标记窗体已经被释放,如果窗体被释放那么必须重新实例化。
 8     if (frm == null || frm.IsDisposed)
 9     {
10         frm = new FrmPerson();
11     }
12     return frm;
13 }
14 ...

 

2、可以用Application.OpenForms["窗体名"]找到(没有的话就实例化)和打开指定窗体。

具体代码如下:

 1 ...
 2 //主窗体中点击“tsmiClass”按钮,打开FrmClasses子窗体。
 3 private void tsmiClass_Click(object sender, EventArgs e)
 4 {
 5     FrmClasses frm = null;    
 6     if (Application.OpenForms["FrmClasses"] == null)    
 7     {    
 8         frm = new FrmClasses();    
 9         frm.MdiParent = this;    
10         frm.Show();    
11     }    
12     else    
13     {    
14         Application.OpenForms["FrmClasses"].Show();    
15     }    
16 } 
17 ... 

 

posted on 2017-08-22 17:33  困兽斗  阅读(250)  评论(0)    收藏  举报

导航