“在.net中轻松掌握Windows窗体间的数据交互(一)”中的几个技术细节

原文请见: http://blog.csdn.net/zhzuo/archive/2004/04/05/22027.aspx

本文讨论原文的几个技术细节。

对于作者所写的从 form2 传值到 form1 的实现中所用的方法:

public Form2(TextBox heckbo,CheckBox heckbox)

{

InitializeComponent();

this.textBoxFrm2.Text = heckbo.Text;

this.checkBoxFrm2.Checked = heckbox.Checked;

this.textBoxFrm12 = heckbo;

this.checkBoxFrm12 = heckbox;

}

private void buttonOK_Click(object sender, System.EventArgs e)

{

this.textBoxFrm12.Text = this.textBoxFrm2.Text;

this.checkBoxFrm12.Checked = this.checkBoxFrm2.Checked;

this.Close();

}

其中作者没有写到对 form1 的修改。由 form2 的构造函数可知,此函数引入了声明了两个形参, heckbo 和 heckbox ,那么对于调用构造函数的 form1 ,对应的按钮点击事件则应写为:

private void buttonEdit_Click(object sender, System.EventArgs e)

{

Form2 formChild = new Form2(this.textBoxFrm1,this.checkBoxFrm1);

formChild.Show();

}

下面来解释此方法的实现细节:

在 c# 中值被分为两种型别,分别是 value 型别和 reference 型别,其中 int,float 等型别被划分为 Value 型别,而数组等型别则被划分为 reference 型别,那么 value 型别和 reference 型别有什么区别呢? 对于 value 型别,当你用一个 value 型别的变量为另外一个 value 型别的变量赋值时,执行了深拷贝,两个变量同时拥有自己的变量值,修改其中一个变量的值对另外一个变量的值没有影响,如:

string a=”abc”;

string b=a;

string a=”cde”;

console.writeline(a);

console.writeline(b);

输出为: cde

abc

然而对于 reference 型别就完全不是这样了,当我们建立一个 reference 型别的变量(如作者程序中的数组)的时候,系统会在受控堆( managed heap )上划分一块区域用以储存这个变量的值,而我们声明的变量名则只保存了那块区域的地址。那么当我们在用一个 reference 变量为另外一个 reference 变量赋值的时候发生了什么呢?被赋值的变量只保存了赋给它值的那个变量的地址,所以两个变量拥有了同一个地址,指向了同一个储存区域。这时,无论改变哪一个变量的值,都会影响另外一个变量的值,这也是作者所用来从 form2 向 form1 传值的方法!

在作者的程序中, form2 的构造函数接受一个 TextBox 的形参和一个 CheckBox 的形参,而这两个形参都属于 reference 型别(一般用 new 创建出来的 object 都属于 reference 型别 , 不过也不绝对)当我们调用构造函数时,实参 TextBoxfrm1 和 CheckBoxfrm1 被传递给函数,而函数的参数只在函数内部有效,所以又创建了两个临时的 object 用以传递参数:

private TextBox textBoxFrm12;

private CheckBox checkBoxFrm12;

接着这两个 object 被形参赋值:

this.textBoxFrm12 = heckbo;

this.checkBoxFrm12 = heckbox;

此时的 textBoxFrm12 和 checkBoxFrm12 分别持有 TextBoxfrm1 和 checkBoxfrm1 的地址,接下来在 button_click() 事件中,将 textBoxFrm12 和 checkBoxFrm12 的值更改:

this.textBoxFrm12.Text = this.textBoxFrm2.Text;

this.checkBoxFrm12.Checked = this.checkBoxFrm2.Checked;

根据上面提到的 reference 型别的特点,对持有相同地址的两个 object 中的一个的内容进行更改将影响另外一个 object 。对 textBoxFrm12 和 checkBoxFrm12 的内容的更改,同时也对 TextBoxfrm1 和 checkBoxfrm1 的内容进行了更改,从而将 form2 的值传递给了 form1 。

那么为什么不直接用 string 字串来传送 TextBox 的值呢?如以下程序:

private string n

public Form2(string s)

{

InitializeComponent();

this.textBoxFrm2.Text =s

n=s;

}

private void buttonOK_Click(object sender, System.EventArgs e)

{

n = this.textBoxFrm2.Text;

this.Close();

}

由前述可知当我们把一个 string 变量赋给另外一个 string 变量时,实际上产生了两个含有相同值的独立 string 变量,当把实参赋给形参 s 时, s 为一个独立于实参的变量,改变 s 的值不会改变实参的值,同样对于 n=s, 改变 n 的值一样不会改变 s 的值。

那么就没有办法用字符串的方法传值么?看下面程序

Form1 做如下更改:

private void form1button_Click(object sender, System.EventArgs e)

{

string m=TextBoxfrm1.Text;

Form2 frm2=new Form2(ref m);

frm2.Show();

TextBoxfrm1.Text=m;

}

Form2 做如下更改:

public Form2(ref string s)

{

InitializeComponent();

s=TextBoxfrm2.Text;

}

将 form2 的 button_click() 事件中除了 this.close(); 语句的其他语句删除。

运行此程序可以将 TextBoxfrm2 文本框中的初值传递给 form1 中的 TextBoxfrm1 。其中原因是使用了传址参数 ref ,此关键字允许为传入的实参设置一个别名,而此别名和实参同时指向同一个值。需要注意的是在调用函数的时候亦必须加上传址参数 ref 。但此方法也有其不完善的地方,它只能将 TextBoxfrm1 的值设为 form2 调用时 TextBoxfrm2 的初值,而对 TextBoxfrm2 值的任何改动,在 TextBoxfrm1 中都无法体现出来,原因在于 ref 所定义的参数 s 只在函数体内可见,如果要使它能够相应 button_click() 事件,则必须定义一个临时字串 m=s, 然后令 m=TextBoxfrm2.Text, 但是这样又等于定义了两个独立的变量,对 m 的改动不会反映到 s 上,也就不会反映到 TextBoxfrm1.Text 上。

如果你有什么好的解决方法,欢迎与我联系: [email protected]

Published At
Categories with Web编程
Tagged with
comments powered by Disqus