由于公司的业务调整,最近不仅开发bs,还有不熟悉的cs,人手也不足,项目还多,对于cs来说,算是小白,虽然是一个人,也是硬着头皮写,拖拽控件,自定义控件。一个项目下来,对cs有了很深的认识,这里好好感谢下老大以及身边的同事,总是在我绞尽脑汁也没想出好的解决方案时来给我指点迷津。
首先介绍下cs的页签功能,毕竟之前学校那会,仅仅是简单的弹出新窗体,关闭就窗体。对于项目中是菜单而言,肯定是要有子界面相互切换的功能,关于这一块,其实就是在主窗体中画一个Pannel(其他的listbox也可以),按钮点到哪里就把对应的子窗体加载到主窗体上的pannel(listbox)中即可,当然子窗体可以选择新建窗体、新建用户控件,如果选择新窗体,需要将FormBorderStyle的属性值设为None,来去掉窗体四周多余的料。操作如下图,设置了两个窗体,一个用户控件。分别命名为form01、form002、form003Con
(注: 初始化的时候执行子窗体的构造函数,Show之后执行Load 函数)
private form001 f1; private form002 f2; private form003Con f3; private void Main_Load(object sender, EventArgs e) { f1 = new form001(); f2 = new form002(); f3 = new form003Con(); } private void btn_001_Click(object sender, EventArgs e) { //设置子窗体非顶级窗体 f1.TopLevel = false; panel2.Controls.Clear(); panel2.Controls.Add(f1); //显示子窗体 f1.Show(); } private void btn_002_Click(object sender, EventArgs e) { f2.TopLevel = false; panel2.Controls.Clear(); panel2.Controls.Add(f2); //设置子窗体铺满父窗体(跟随父窗体变化而变化) f2.Dock = DockStyle.Fill; f2.Show(); } private void btn_003_Click(object sender, EventArgs e) { //用户控件: 不需要设置层级、调用show方法,本身就是控件 panel2.Controls.Clear(); panel2.Controls.Add(f3); f3.Dock = DockStyle.Fill; }
根据以上操作,窗体在放大的时候,子窗体 f1保持初始化大小,而子窗体 f2、f3随随着主窗体变大而跟着变大。效果图如下
做到这里效果是能达到了,但是会有一个问题,就是对控件事件的控制,比如子窗体1,2,3 中分别有一个按钮控件,这些按钮按下去要获得主窗体的一些参数信息,常规方法是在子窗体后台的构造函数中加入参数,然后父窗体New 子窗体对象的时候传递值进去。这种实现方法没问题,但是有时候会遇到这种情况,父窗体需要子窗体的某些控件信息,拿到这些信息后要在父窗体中进一步处理后显示。这种时候的处理其实是将子窗体中按钮的触发事件加载到父窗体中来实现。代码如下
private void btn_002_Click(object sender, EventArgs e) { f2.TopLevel = false; panel2.Controls.Clear(); panel2.Controls.Add(f2); //重置子窗体的按钮点击事件 到 f2btnQuery方法中 f2.btnQuery.Click += new System.EventHandler(f2btnQuery);
//设置子窗体铺满父窗体(跟随父窗体变化而变化) f2.Dock = DockStyle.Fill; f2.Show(); }
private void f2btnQuery(object sender, EventArgs e) { //将子窗体2中待编辑控件的Modifiers 属性设置为 Public f2.label1.Text = ""; f2.label2.Text = ""; var value = f2.textBox1.Text.Trim(); }
此外,winform程序运行在不同分辨率的电脑上,为了兼容,基本都是要做窗体自适应功能。之前在网上寻找了很多例子,有的是对 Dock和 Anchor 两个属性进行操作,针对面板来说还凑合,但是对于里面的textbox等小控件来说在实际上单靠这两个完全行不通。有的文章来计算一下针对一些界面简单的小Demo,看着还行,但是在实际项目的开发中,则完全不行。有的文章则是通过计算控件的宽高来达到等比缩放的比例,对于简单的窗体还好,但是对拥有各种复杂嵌套的窗体来说,就显得有些捉襟见肘。实际项目中可以直接通过画表格来达到缩放效果。工具箱列表中有一个TableLayoutPanel 控件,就是用来制作表格的。在窗体上拖一个该控件,设置Dock为Fill 铺满,然后将窗体的控件填充到表格中,如果是Label 可以直接拖入,如果是其他button、textbox之类的,建议先拖一个pannel 来作为底,再在pannel上放入button、textbox等控件。当然并不是每个控件都会只占一个单元格,这就涉及到行合并,列合并。对于TableLayoutPanel 控件本身,并没有像Excle表格那样提供该属性。但是也并非没有解决方案,比如先拖动一个pannel 在一单元格上,设置ColumnSpan(跨行)、RowSpan(跨列),拖动 pannel 合并对应的行列铺满(Dock 为Fill ),在将其他控件放置在pannel上即可。如下:
当然这是对于简单的界面,而对于那些拥有复杂控件的窗体来说,操作也很简单,只需要稍稍加一个占比即可。这里做了一个测试窗体,如下
如上图所示,不难看出这是由 4个TableLayoutPanel 所组合的窗体,首先是一个大表格,一行三列,分别为分类一,分类二,分类三,然后在该三列下分别有一个三行一列的TableLayoutPanel 控件。对于缩放而言点击右上角设置列和行的占比,还能和固定长度进行混合设置,我这里设置的三列占比 23%、50%、27%,每列中最上面一行设置固定长度26,剩下的行凑足100%,下面我们来最大化一下和上图初始化的窗体比较一下效果
效果还行,基本是按照自己把控的尺寸变化。当然每个列中还会放置很多文本框、标签、下拉列表等等的控件,如果实在是很多,建议再在某个单元格中嵌套一个 TableLayoutPanel 控件,再次进行拆分,pannel进行填充跨行列,而对于这些控件,如果同样希望等比例缩放,则设置Anchor 上下左右全选即可。如此以来,变可以彻彻底底的解决winform 窗体的自适应困局。
由于本人在CS开发方面还属于小白水平,独立开发项目时在功能完成的情况下对这些界面布局设置上面走了很多弯路,这里记录一下,毕竟作为空巢老人,指不定明天就忘记了,如果能对其他人有丁点的帮助,那便甚是欣慰。