技巧1,合理使用控件的Tag属性几乎所有winform控件有都名为object类型的Tag属性,此属性多数情况下用来承载完整的数据源,相当于WEBFORM页面中hidden控件的作用,举个简单的例子
textBox1.Text=info.UserName;
上述代码非常简单,将实体的属性赋值给一个文本框,而此实体还有其它属性,文本框无法显示那么多了,不过一会儿其它地方还需要使用实体的其它对象,那此时就可以把该实体直接赋给文本框的Tag属性,类型为object,代码如下:
textBox1.Text = info.UserName;textBox1.Tag = info;
这样再次使用实体的时候就可以从控件的Tag属性中取了,如
PersonEntity info = textBox1.Tag as PersonEntity;
当然了,也完全可以把info设计为属性,但有时候这样做可能要添加很多这样的属性,此时就是Tag的用武之地了
技巧2,模态窗口使用DialogResult关闭窗口如下应用场景,需要弹出一个窗口来,其中需要客户输入处理一些数据后返回,代码如下FrmConnection frmConnection = new FrmConnection(); if( frmConnection.ShowDialog() == DialogResult.OK && frmConnection.Info != null ) { frmDataBase.Info = frmConnection.Info; InitializeCustomControl( frmDataBase ); }
在弹出的窗口中,给它自己的DialogResult属性赋值,窗口即会自动关闭,通常情况自己关闭也可以,不过调用了Close或Dispose方法后,弹出的窗口对象会销毁,此时再调用它的其它属性什么的,会报"无法访问已释放的资源"的异常
技巧3,临时挂起控件更新同技巧1一样,几乎所有的"容器控件"都有SuspendLayout()方法和ResumeLayout()方法,这两个方法是做什么的呢?这两个方法在XXX.Designer.cs代码中最常见,就是设计窗体时VS自动生成的代码里,它是临时挂起控件更新,然后修改控件属性,如添加子控件,改变大小等等操作,全部操作完成后再调用ResumeLayout(false)方法,这样将控件"只更新一次"即可,效率上会提高不了,有点像拼接N个INSERT 语句,然后只连接一次数据库执行全部,而不是连接N次,执行N次,效率自然不咋地了,呵呵! 记录学习中的点点滴滴,一次书写,终生享用,人人为我,我为人人
textBox1.Text=info.UserName;
上述代码非常简单,将实体的属性赋值给一个文本框,而此实体还有其它属性,文本框无法显示那么多了,不过一会儿其它地方还需要使用实体的其它对象,那此时就可以把该实体直接赋给文本框的Tag属性,类型为object,代码如下:
textBox1.Text = info.UserName;textBox1.Tag = info;
这样再次使用实体的时候就可以从控件的Tag属性中取了,如
PersonEntity info = textBox1.Tag as PersonEntity;
当然了,也完全可以把info设计为属性,但有时候这样做可能要添加很多这样的属性,此时就是Tag的用武之地了
技巧2,模态窗口使用DialogResult关闭窗口如下应用场景,需要弹出一个窗口来,其中需要客户输入处理一些数据后返回,代码如下FrmConnection frmConnection = new FrmConnection(); if( frmConnection.ShowDialog() == DialogResult.OK && frmConnection.Info != null ) { frmDataBase.Info = frmConnection.Info; InitializeCustomControl( frmDataBase ); }
在弹出的窗口中,给它自己的DialogResult属性赋值,窗口即会自动关闭,通常情况自己关闭也可以,不过调用了Close或Dispose方法后,弹出的窗口对象会销毁,此时再调用它的其它属性什么的,会报"无法访问已释放的资源"的异常
技巧3,临时挂起控件更新同技巧1一样,几乎所有的"容器控件"都有SuspendLayout()方法和ResumeLayout()方法,这两个方法是做什么的呢?这两个方法在XXX.Designer.cs代码中最常见,就是设计窗体时VS自动生成的代码里,它是临时挂起控件更新,然后修改控件属性,如添加子控件,改变大小等等操作,全部操作完成后再调用ResumeLayout(false)方法,这样将控件"只更新一次"即可,效率上会提高不了,有点像拼接N个INSERT 语句,然后只连接一次数据库执行全部,而不是连接N次,执行N次,效率自然不咋地了,呵呵! 记录学习中的点点滴滴,一次书写,终生享用,人人为我,我为人人
在更新listview等控时,也会用到beginupdate()和endupdate(),据说是为了提高效率,有所体会,但是会闪
其实还有个简单办法,就是先设置listview的Visiable=false,然后调用SuspendLayout方法,
再然后调整listview的各个属性,完毕后调用ResumeLayout(false)方法,最后再设置listview的Visiable=true,
这样的效果是"卡"一下,但不会闪,为了不卡,还可以把上述所有操作放到子线程里操作,这样也不卡也不闪,但是使用多线程会带来其它问题
如跨线程操作控件UI等问题,会带来更多的编码工作,不是非常看重这个,一般不使用,作为一个思路还行,呵呵
既然Visiable=false就不需要调用SuspendLayout方法了,当Visiable=false时控件显然是不会被重绘,所以这时候调用SuspendLayout是没意义的。
怎么说呢,不仅仅上述三个技巧,所有的"实现方法"都有"最适合使用"的场景,在最适合使用某技术的场景中使用就是最好的解决方案,相反就不是了,
1,在最适合使用它的上下文中使用就非常好,过度使用,强行使用效率不佳,举个适合使用它的场景,如TreeView中的TreeNode的Tag可以设置为实体对象,这要在TreeView的事件e里可以找到Node,继而可以从其Tag中获取到实体对象,对这种方法对应的别一种方法,如写一个Dictionary<string,实体>来保存,在使用的时候根据TreeNode的Name或Text到字典里遍历获取以好得多,您觉得呢?
2,这个是昨天写代码时"不小心"发现的一个现象,最后一再测试发现其规律,故写出来让更多的人的知道,同时也希望更多的人指出它的适用范围,指出我理解中的不足
3,我能想到的最佳的方法也就是14楼的回复了
这种场景不适合用Tag,代码的可读性太差。最佳做法是重写 TreeNode,扩展你所需要的属性,在TreeView中添加你自己的TreeNode,重写一个TreeNode代码量顶多10多行,换来的好处是非常好的可读性和扩展性。
那Tag什么时候适用呢?因为几乎所有WINFORM控件都有Tag属性,使用到的全部重写?显然也不太好~您觉得呢?
偷懒的时候用。不推荐使用Tag的原因:
1.可读性不佳,这不用说,一个窗体里面,这个控件的Tag是id,另一个控件的Tag是实体,时间久了,看了会头晕。
2.扩展性不佳,比如你上面说的TreeNode,放了一个实体在Tag上,以后你又使用到一个值,就没地方放了,这时候你就不得不更改你原来的设计模型了。当然,用Tag很方便了,所以在小地方我还是会用,比较会用在很小的窗体里(代码量20行左右),这种时候使用对可读性基本不造成什么影响。
{
private DataView dataview; public Form1()
{
InitializeComponent();
} private class MyTreeNode : TreeNode
{
public int Id { get; set; }
}
}三行代码为TreeNode增加一个id,而且声明为private class,保证对其它窗体不产生任何影响。
楼主我有个问题,我的一个窗体上有很多控件(二十几个吧),这些控件都是设计的时候拖上去的。在窗体SHOW的时候要很慢才能显示完整个窗体,请问楼主有没有好的办法解决?
no no
第一个疑问:这个完全看个人编程习惯了,如一般情况下Tag都存储完整的实体,而不刻意去部分,目的就是在需要的时候可以获取到整个实体对象,基本不会只放实体的一个属性
关于第二个疑问:暂时想像不到这样的应用场景,但我相信,即使有这样的应用场景,则必定是其它地方设计的不够科学或合理一般情况下,通常情况下,多数情况下,没特别的要求的话,Tag是用来存储完整数据源的,这似乎也是设计它的初衷,这个可参考Tag的提示说明
如果某控件只用来显示某实体,那么该控件的Tag最适合放该对象了,而不是乱放,基本原则等同变量的存放,在有使用它的上下文中使用它对"临时挂起的控件更新的小技巧"的批评虚心接受,谢谢~
因为对于非模态窗体(.Show出来而不是.ShowDialog出来的),对DialogResult赋值后不会自动关闭窗体,这样存在不一致性。另外,由于给DialogResult赋值后自动Close是在消息回圈中检查的,所以很多情况下,比如系统一直忙,或多线程,甚至在窗体使用了Timer控件时都会有问题