窗体间传值及随机数生成器小记
近来总看到有兄弟在论坛中发帖,询问关于窗体间传值的问题,我总结了下所掌握的几个方法,以及其优劣,归纳如下,另外还有一小部分内容为随机数生成器Random的使用的技巧,篇幅不大,故合纂一起。本文旨在学习归纳之用。 窗体间传值要弄清楚到底是哪个对象的问题,否则容易传错值。就比如窗体对象loginFrm为登陆窗体,想把当前的登陆用户信息传递给主窗体mainFrm,但是却实例了一个新的对象loginFrm把里头的信息传递给了mainFrm,所以得到了一空值,颇有刻舟求剑的味道,不同的内存空间就比如湖水的宽广一样,存放着不同的对象,彼此要分清楚。窗体传值的前提是,要传的字段,在类里面的访问修饰符必须是public(如果在源窗体内传值则例外,参见下列常用方法2)。
常用的方法:
1. 静态变量,在窗体里Class Form1中,写入一个静态变量A,可以给其赋值,那么在这个项目中,就可以通过Form1.A来调用。不推荐此种方法,不太安全。
2. 比较稳妥的方法,就是在传值的过程中,首先在被传值窗体form2中,建立一个公有属性B,做为接收者。在form1里实例form2时,把需要传递的值A赋给新实例form2.B,或者是通过Form2类的构造函数传递,方法很多,此种传值较为安全(推荐)。
3. 若是要得到一组固定的数据,那么可以写成一个公有的带返回值的方法,在源窗体中。然后在目标窗体中实例源窗体对象,调用此方法获得数据,此方法虽不同于静态变量,但有异曲同工之妙,可以不必强调对象。其缺点是,方法体内传递数据为固定的,不能变通。
4. 查询对话框,大家都用过记事本,里头有个查询功能,就是当选中一段文字时,打开查询对话框,就会在查询对话框中显示选中的那段文字,其代码实现为:
在Form1中:我们要把一个文本传递给Form2窗体,假定为passText
public string passText
{
get{ return textBox1.Text;}
}
Form1中还有个按钮button1在其点击事件中有:
private void button1_Click(object sender,EventArgs e)
{
Form2 f2 = new Form2(); //呃。。这个就不用说了
f2.Owner = this; //设置附属,好搭关系~
f2.Show(); //看得出来撒
}
在Form2的对象中:
假设有个文本框txtBox1,现
private void form2_Load(object sender,EventArgs e)
{
//通过目标窗体,找到拥有它的源窗体,得到的是一个object
对象,要转换成Form1这个类型,就可以得到它的公有属性passText拉。
textBox1.Text = ((Form1)this.Owner).passText;
}
这样当我们打开Form2时,就会在其文本框中,显示Form1的文本框信息了(想要做到查询对话框显示选中文本的效果,只需要在把passText 的属性改成textBox.SelectedText即可.)
这种方法的主要好处是在于,我们能在目标窗体的对象中,找到源窗体的对象。而有别与上面两种情况。
5. 窗体间同步传值的实现,就是实时更新两个窗体间的信息,有心的朋友可能发现,既然能在目标窗体中,找到源窗体,那么我们还可以通过源窗体来控制目标窗体,从这里面突破,就能达到此效果了。代码如下还是依照4例:在Form1中:
程序代码:
public partial class Form1 : Form { public Form1() { InitializeComponent(); } public string passText { get { return textBox1.SelectedText.Text; } } private void button1_Click(object sender, EventArgs e) { Form2 f2 = new Form2(); f2.Owner = this; f2.Show(); } private void Form1_Load(object sender, EventArgs e) { } private void textBox1_TextChanged(object sender, EventArgs e) { if(this.OwnedForms.Length != 0) (this.OwnedForms[0] as Form2).selectText = textBox1.Text;/*OwnedForms是一个数组 ,表示当前对象拥有的子窗体数组,同样要把通过下标得到的元素转换为Form2类型。*/ } } } namespace WindowsApplication1 { public partial class Form2 : Form { public string selectText { set { textBox1.Text = value; //设置一个属性,让form1操作 } } public Form2() { InitializeComponent(); } private void Form2_Load(object sender, EventArgs e) { textBox1.Text = ((Form1)this.Owner).passText; } } }
最后,要说一下的是,在传值的时候,不光可以传变量属性,还有个很好的东西,每个窗体都有个Tag属性,是一个标记,object类型的,我们可以把一个类赋给它。这样就为我们的代码,提供了极大的便利,大家可以依据上面4种传值方式,进行使用。
探究随机数生成器
这玩意,当初接触时,很是好奇,遂决心研究一下,在我们的代码中,很普遍的需要运用到一个随机生成的数,而大家平时都用的它最普遍的随便new一个Random对象,就开始Next了。这里我主要来补充一下,就以我研究得过程来说明吧。这样既阅读起来有趣味,也便于逐步理解。
话说又是一个月黑风高的夜晚,一个人在宿舍守着青灯黄卷。看着书上的一句话,引起了我的注意,Random rd = new Random(DateTime.Now.Ticks)为什么要放上这么一个参数呢,一般我认为都没要参数就直接搞了Next这里的解释是,这个参数是足够大,而且一直在变化,能让我们更充分得到随机范围内的数。我就不知道这个Ticks是干嘛的,查MSDN发现是说从0001年起到现在以每100毫微秒为间隔的值,我当时就晕了,那是多么大个数,我打印了一下,果然很大,而且还是一直在变化,100毫微秒,比毫秒还小,
我先除了1000得到毫秒,又除1000得到秒。。。一直除到年,发现,还真够年份了。。。
接着我又想,真的是因为它大,或者说在变就有用处么?
继续查阅MSDN,读了有参数和没参数的两种。还是没能理解什么叫种子值,我做了两个文本框,两个按钮,分别控制输入,范围是10,我发现都有重复出现的,可能是范围太小,调整到Next(255),两边继续打印,发现左边是有种子值(即参数)的,有一个188重复了(嗯。很好的数字),右边没有重复的,难道这个就是规律?未免有点太搞笑了吧。继续打印,觉得这样很不科学,我想放弃了,不管它,可是还是没能研究出个所以然来,很不爽,刚准备关掉MSDN时,我又读到一句话,有相同的种子值时,生成的序列将是相同的,我尝试着试了一下,发现果然如此。
Random rd = new Random(N);当N固定时,生成的都是同一列数字,不改变的。
同时我又发现,两个无参的rd1和rd2生成的数据也一样,但是另一组对话框的无参的数据rd3又生成的数据组和rd1,rd2的不同。一开始,我只知道无参时,种子值和时间有关系,但是这点我很困惑,为什么两个按钮里的3个随机数在一起的就相同,不在一起的rd3生成的就不同呢,我本来又准备放弃,可就当我再次准备关MSDN时,一个信息又给了我灵光一闪:
这不就是时间间隔Ticks么。它是一直在变,而且和无参的种子值一样都是派生自系统时间。我想会不会是在button2控制的rd1和rd2是由于时间太短,还没来得及变的原因,接着我又把MSDN下面的方法复制运行了一遍,发现它也是实例的两个无参的Random,但是生成的数据组不一样,我分析了下,可能是它包装在两个方法内打印,那么种子值可能产生时间差所致。这也符合我先前的猜想,我在button2里实例rd1和rd2时,搞了个Sleep(500)延迟线程500毫秒的操作,果然,再次打印的3个数据组数据都不相同,那么根据这个猜想,本文开头的以时间的Ticks做为参数的话,我把它作为rd1和rd2的参数,那么去掉延迟,也应该打印相同数据了,经实验,果然如此,有股顿悟的感觉充盈全身,酣畅淋漓。至此可以说,Random的参数和大小无关,只和变化有关。
总结如下:1.参数固定时,所产生的是固定的数组。
2.无参数的时候,以时间为种子值,不同时刻的数组都不相同,所以不必实例几个Random出来。但是要使用时错开时间制造一个时差。
以上是我学习里的一点积攒,说不上什么高深的技术,学会了, 也只用于项目的一小部分,不过知识就是这样累积起来的,不积跬步,无以至千里。花了2个小时写出来的,难免有疏漏之处,望大家积极讨论,群策群力共同提高。
2008年10月5号
[[it] 本帖最后由 小仙 于 2008-10-5 15:12 编辑 [/it]]