
在C#的WinForm编程中,避免不了多窗口的应用,说起来也算简单的,但是想熟练运用就麻烦一些,先将我的体会总结如下:
1、调用窗体与被调用窗体新建一个WinForm项目后,Visual Studio自动生成一个Form1。我们可以再手工再添加一个窗体Form2,设置好其它控件后,利用如下代码,显示新窗体:
Form2 myForm = new Form2();myForm.Show();这时,Form2就显示出来了。此时,我们称Form1是“调用窗体”,Form2是“被调用”窗体。
当然,也可以代码的方式显示窗体:
Form myform = new Form();myform.Show();注意:这时两个窗体之间的关系是平等的,没有“父子”关系,也没有包含关系。一般情况下,调用窗体只能访问被调用窗体的属性、方法,但不能访问被调用窗口内部的控件对象。
测试:
Console.WriteLine("父窗体:"+this.Parent);Console.WriteLine("拥有者:" + this.Owner);一般情况下,都会返回空。
2、窗体的本质我们用Visual Studio可视化工具制作的窗体,实际上就是一个“类”,是派生于System.Windows.Forms;的特殊类。我们可以看到如下代码:
……public partial Form1 : Form……由此可见,我们可以直接修改代码中冒号后面的Form,改为我们自己定义的窗体。这个方法可用于程序“皮肤”的自定义。
3、调用窗体访问被调用窗体内部对象了解窗体也是类以后,我们就可以将被调用窗体的内部对象,“Modifiers”由默认的“private”改为“public”,自定义的变量也如此,这时候调用窗口就可以访问被调用窗体了。
4、被调用窗体访问调用窗体(1)被动方式,也就是调用窗体主动给被调用窗体一个“接口”
i.调用窗体定义“静态”变量,并将开放的变量复制
ii.在被调用窗体中,使用:调用窗体名.静态变量名.数学(方法)的形式调用
例如:
……//调用窗体public partial Form1 : Form{public static Form1 mainFm;public static Button mainBtn;public Form1(){InitializeComponent();mainFm = this;mainBtn = this.button1;}……//被调用窗体Form1.mainFm.Text = "标题";Form1.mainBtn.Text = "按钮";(2)被动方式,由被调用窗体直接访问调用窗体
这一点尤其是在编写自定义类库时尤为重要,因为写代码时,无法预料使用类库者,是否会在调用时开放“主动接口”。
i.在调用窗体中,设置public类型的变量,用于接收类库调用时的赋值,可以直接是窗体,也可以是控件。
ii.如果是窗体,就可以在被调用窗口中直接使用,否则可以利用FindForm()获取调用窗体的对象
例如:
//被调用窗体……public Control myPicture;……//调用窗体……Form2 myForm = new Form2();myForm.myPicture = this.pictureBox1;myForm.Show();……//被调用窗体……Console.WriteLine("调用窗体:" + myPicture.FindForm());……5.调用窗体带着被调用窗体移动在调用窗体的Move事件中,设置被调用窗体的Top、Left的值
6、被调用窗体跟着调用窗体移动//被调用窗体中public Control VideoWindows;//由被调用窗体赋值VideoWindows.Parent.Move += new EventHandler(OSDMove);//监听调用窗口移动事件7、调用窗体包含被调用窗体如果为了实现另被调用窗口始终覆盖在调用窗口上,可以使用如下两个命令,哪个都行
this.AddOwnedForm(myForm);myForm.Show(this);8、被调用窗体包含于调用窗体中如果开发类库,就要让被调用窗口自己操作
//被调用窗体
……public Control myPicture;this.Owner = myPicture.FindForm();//设置拥有此窗体的对象。调用窗体,是通过传递过来的控件,再查找改控件所在的窗体获得的……注意,Owner只接受窗体类型数据,如果是控件类型,需要转换,例如:
this.Owner = (Form)myPicture.Parent;9、被调用窗体覆盖在调用窗体上参考上面的“包含”关系。如果调用窗体包含了被调用窗体,这时被调用窗体始终覆盖在调用窗体上
10、被调用窗体嵌入调用窗体空间内……Form2 myForm = new Form2();myForm.TopLevel = false;//指示子窗体非顶级窗体this.panel1.Controls.Add(myForm);//将子窗体载入panelmyForm.Show();……11、子窗口显示方式MyForm.Show();MyForm.ShowDialog();以上两种方式都能显示新窗口,但是第二种类似MessageBox.Show(),它吧调用窗体的进展阻塞了,调用窗口这时不能响应用户操作。
12、窗体循环操作推荐Time控件,否则效果会出不来,甚至影响调用窗口的使用效果。
13、窗体透明必须保证窗体的BackColor与TransparencyKey设置一直。异形窗口可采用带有透明信息的PNG图片。
14、控件透明设置控件的BackColor为Transparent
设置控件的Parent主控件
重新移动调整一下控件位置(非常重要!否则控件不显示!)
如果只需让控件在窗体上透明,只需a)即可。但是如果控件覆盖在pictureBox或panel上,就需要上面的每个步骤了。
因为默认情况下,控件的父控件就是本事说在的窗体,这时BackColor为Transparent就起作用,但是如果覆盖在其它控件上,就需要后面的两个步骤了。
第三个步骤为什么呢?原因也是父控件的问题,默认是窗体,控件的位置就是以窗体为基准。第三个步骤就是让VS重新按照“父”控件为基准再设置一次。
15、其它:(1)Irisskin皮肤
使用Irisskin类库设置窗体皮肤时,有时个别窗口或者控件,不希望也使用这个皮肤,这时可以对象的将Tag属性设置为9999,这是默认值,如果需要修改,可以在修改SkinEngine控件的DisabledTag属性。
(2)窗体淡出淡入
设置窗体的Opacity值,范围0~1。例如:
//淡出Time控件TimeShowOSDif (this.Opacity < 1){this.Opacity=this.Opacity+0.1;Application.DoEvents();Console.WriteLine(this.Opacity);}else{TimeShowOSD.Enabled = false;}//淡入Time控件TimeHideOSDif (this.Opacity > 0){this.Opacity =this.Opacity-0.1;Application.DoEvents();Console.WriteLine(this.Opacity);}else{TimeHideOSD.Enabled = false;}(3)防止进程堵塞
Application.DoEvents();(4)小心Panel
由于Panel是容器,因此如果想让控件覆盖其上,就要在Panel外面画好再用键盘移动过去,否则可能会导致控件进入了Panel中了。
(5)窗体置顶
修改窗体TopMost的值为真