[唠叨两句]窗体间传值及其同步更新显示

 

今天唠叨两句一个特别经典的话题:“窗体间传值 及 同步更新两个窗体间的数据”,作为菜鸟无论是知识、技术、还是能力都有限,说的不好、望大家莫笑。

我们老师在给我们讲课时惯用的一个套路就是:以实例由简到繁、由易到难,将知识点及其用法贯穿于始终。今天我也献丑试一试,嘿嘿… 见笑、见笑!

 

 

窗体简单设计如下:

父窗体 :Form1  包含两个控件:TextBox类型控件,Name属性 txt1; Button类型控件, Name属性 btn1;

子窗体 :Form2  包含两个控件:TextBox类型控件,Name属性 txt2; Button类型控件, Name属性 btn2;

 默认启动父窗体 Form1

 

 

好了、有了上面的两个窗体之后就可以,真正的实验就可以开始啦!

 

第一步目标:单击btn1时,显示Form2 窗体 并将Form1 窗体中txt1的文本值 赋值于 Form2窗体的 txt2控件。

 

 

 

【先多唠叨两句、简单的思考一下:】

其实这个过程就是将父窗体的一个数据传到子窗体中、然后在控件中显示出来,即属于“父传子”。

 

而类于类之间进行数据传递(或者说是窗体与窗体之间、窗体的本质就是类),无非是借助字段(公有的)、属性、构造函数、索引、方法、委托、事件完成的,当然还有可能是其他的方式、不过我想本质上还应该是借助了如上所说的方式。

 


字段:

字段、在我看来它是一个全局变量,习惯上使用private 关键字进行修饰,它在类实例化时(即执行new的时候)被初始化并赋值,此后可在类内部的任意位置访问该字段。

属性:

属性呢,它 等效于 两个特殊的方法,这两个个特殊方法分别满足如下条件(以string类型为例):


 当执行get 访问器的时候、它等效于 一个 没有参数 并且返回值为 string类型的 方法;

 当执行set 访问器的时候、它等效于 一个 只有一个string 类型的参数(这个参数是匿名的用Value关键字代替)并且 返回值为void 类型的 方法。

 

【注意:】

1、属性可以是任何类型的、当然 void 类型除外。

2、属性的get  和 set访问器 可有可无,但必须有其中一个。
3、在可以在get 或者是 set访问器里它不只是对一个字段的简单读写,而且可以实现好多功能

构造函数:

构造函数也可以称为特殊的方法,其特殊性在于返回值的特殊、构造函数的没有显示的表名其返回值,但却有硬性的定义了其返回值为其所在类的类型、或者是 所在的结构的类型(因为在结构中存在默认的无参构造函数、在结构中不可以显示的声明无参构造函数、但可对其进行重载)。


构造函数也可以像方法一样重载。

 

构造函数会在使用new 关键字实例化 实例的同时隐式的调用。

索引:

由于他们可以都有get和 set 访问器的缘故,索引也可以看作是两个特殊的方法,这一点与属性很相似。在这一点上还有一点不同的就是 索引显示的定义了一个形参,并且形参的类型可以与返回值的类型可以不相同,而属性则其参数与返回值的类型是相同的。

并且,在访问方式上 索引也不同于属于、字段,字段和属性是通过"."运算符进行访问、而索引是通过"[]"运算符进行访问。

方法:

方法这个东东太深了、涵盖面也太广了、面向对象语言的三大特征 继承、封装、多态 样样都离不开方法,好多东东还未能理解、在此不便多说。
只提一点:方法的参数中可以加 ref 、out 关键字 使之传递引用,但是this 关键字不可以与 ref 或 out 关键字一起使用,因为 this 关键字是只读的,还有属性与索引也不允许使用ref 、out 关键字。

委托:

委托使用 delegate关键字进行定义,它和结构、类一样也是一种类型,都可以作为类的成员变量去使用。

 

依我的个人的理解、委托就是对特定方法签名的方法的引用,当执行委托时、委托会依次调用执行该委托所指向的方法(我这里说“依次”、是因为一个委托实例可以同时指向多个特定方法签名的方法、称之为多播委托,这需要使用 =、 +=、 -= 运算符的配合使用)。

 

委托、委托、委托,顾名思义就是委派别人,托付别人做某事,也就是说实现细节交给别人、别的方法。

 

说的再形象一点就是:委托就是一个公司的老板,它所指向的方法就是这个公司的员工,例如下列情况、老板发话了“十天后、项目交工,赶紧把他们弄完!”,这时老板这个“委托”发生了,并且员工们(委托指向的方法)也开始加班加点的工作,等项目做完后交工。如果这个委托是同步执行的,等十天、或者员工们做完项目交工后 该委托执行完毕;但是如果委托是异步执行,当老板说完话之后,委托就执行完毕了。

事件:

事件 与 委托很相似,它使用Event关键字进行定义,并且也可以作为类的成员变量去使用。

在用法上它只允许使用+= 和 -= 运算符、而不可以使用 = ,而+= 、-= 的右边都是委托实例,也就是说当事件被触发时、它会调用相应的委托去执行相应的操作。

 

对于事件也可以这样理解:一个软件公司的业务人员拉来一单生意,当业务人员告诉老板说 生意来了、这是老板就会通知某个项目经理“这个项目、你来负责!”,由此看来事件也是委托、是一种特殊的委托,或者称委托是事件执行过程中需要的一部分。

 

 

 

唉,不知不觉的说了这么多废话了、赶紧步入正题。

 

刚刚也说过了、这个传递过程是一个“父传子”的过程,我优先使用了构造函数、至于原因和争执、我想也是必然也有的,出于个人喜好、我选择了构造函数,至于代码嘛、也简单、如下:
 

目标一

单击btn1时,显示Form2 窗体 并将Form1 窗体中txt1的文本值 赋值于 Form2窗体的 txt2控件的Text属性。

Form1

 

代码
 
        
public partial class Form1 : Form

{

private Form2 frm2; // 声明一个 Form2类型的变量



/// <summary>

/// Form1构造函数

/// </summary>

public Form1()

{

InitializeComponent();



}

/// <summary>

/// btn1 单击事件 处理方法

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void btn1_Click( object sender, EventArgs e)

{

// 显示Form2 窗体 并将Form1 窗体中txt1的文本值 赋值于 Form2窗体的 txt2控件



this .frm2 = new Form2( this .txt1.Text.Trim()); // 实例化Form2 类型的变量

this .frm2.Show();

}

}

 

 

Form2

 

 

   

代码
 
        
public partial class Form2 : Form

{

/// <summary>

/// Form2 默认生成的构造函数

/// </summary>

public Form2()

{

InitializeComponent();

}

/// <summary>

/// Form2 重载 构造函数

/// </summary>

public Form2( string txt)

{

InitializeComponent();

this .txt2.Text = txt.Trim();

}

}

 

 

嘿嘿、挺简单、目标完成。

 

目标二、单击btn2 将Form2 窗体中txt2控件的文本值赋值于Form1窗体的txt1控件的Text属性

【简单的思考一下:放心吧、这次不会有太多废话哦】

这个过程就是 “子传父” 的过程,要想在子窗体里访问父窗体的某一个成员变量、肯定需要在子窗体里得到父窗体的一个实例,然后通过实例 的 "." 运算符 调用某一个成员变量。 但是 txt1是private的呀,咋办? 改成public的? 不太好!还是用属性将txt1的 Text 属性单独公开 吧!好啦,看代码。

 

目标二

单击btn2 将Form2 窗体中txt2控件的文本值赋值于Form1窗体的txt1控件的Text属性

Form1

 

代码
 
        


/// 改动很小的哦, 添加了一个string类型的属性

/// 修改了Form2的构造函数

public partial class Form1 : Form

{

private Form2 frm2; // 声明一个 Form2类型的变量



/// <summary>

/// 用于访问该窗体中txt1控件的Text属性

/// </summary>

public string Txt

{

get { return this .txt1.Text.Trim(); }

set { this .txt1.Text = value; }

}



/// <summary>

/// Form1构造函数

/// </summary>

public Form1()

{

InitializeComponent();

}

/// <summary>

/// btn1 单击事件 处理方法

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void btn1_Click( object sender, EventArgs e)

{

// 显示Form2 窗体 并将Form1 窗体中txt1的文本值 赋值于 Form2窗体的 txt2控件

this .frm2 = new Form2( this .Txt, this ); // 实例化Form2 类型的变量

this .frm2.Show();

}

}

 

 

Form2

 

代码
 
        
public partial class Form2 : Form

{

private Form1 frm1;



/// <summary>

/// Form2 默认生成的构造函数

/// </summary>

public Form2()

{

InitializeComponent();

}



/// <summary>

/// Form2 重载 构造函数

/// </summary>

public Form2( string txt, Form1 frm1)

{

InitializeComponent();

this .txt2.Text = txt.Trim();

this .frm1 = frm1;

}



/// <summary>

/// btn2 单击事件 处理方法

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void btn2_Click( object sender, EventArgs e)

{

// 将该窗体中txt2 控件的文本值 赋值与 Form1窗体的 txt1控件的文本值

frm1.Txt
= this .txt2.Text.Trim(); // 这是重点

}

}

 

 

 

当写完上面的代码后、暗自发笑、嘿嘿,目标完成。

突然间 鼠标单击了一下Form1窗体的btn1按钮,咿? 咋又出来一个窗体呢? 嘿嘿、差点忘了… 后面的不说了、Repair bug 让Form1 中的 数据可以不断的传递到 Form2中,至于方法嘛、简单,仿照Form1、在Form2中 公开一个属性用来访问Form2中的txt2的Text属性,然后将实例化Form2 的代码放在 Form1 的 Load 事件里即可。

 

 

小节:

窗体间数据传递:       

“父传子”借 “构造”;“子传父” 访 “属性”;当然它们不是惟一的选择、而是这样的选择很方便、代码量相对较少,用构造函数传递有一点需要注意、因为构造函数在它在一个实例的生命周期中只被隐式的调用一次,所以它只能向子窗体中传递一次数据,如果是传递多次建议使用属性、更甚至是方法。


反过来再想一想,这只是两个窗体间进行数据传递,要是三个、四个窗体甚至更多的窗体间进行数据传递,怎办呢?

我个人认为一个不错的方法,那就是 属性 +  事件,大致思路如下:
定义一个数据类,类里面有一个私有字段、一个公有属性、一个公有事件,在属性的set访问器里触发事件,然后在需要获取数据进行数据同步的地方 侦听该事件即可。一旦事件发生、在事件的处理方法里更改相应的UI显示就可以啦。

 

目标三

使用属性+ 事件的方式实现数据同步

DataClass

 

代码
 
        
/// <summary>

/// 数据类

/// </summary>

public class DataClass

{

/// <summary>

/// 公有事件 在字段值被改变的同时触发

/// </summary>

public event EventHandler ValueChanged;



/// <summary>

/// 私有字段

/// </summary>

private string str;



/// <summary>

/// 公有属性

/// </summary>

public string Txt

{

get { return this .str; }

set

{

this .str = value;

if ( this .ValueChanged != null )

{

this .ValueChanged( this .str, null );

}

}

}

}

 

 

Form1

 

代码
 
        
public partial class Form1 : Form

{

private DataClass data; // 声明一个数据类



private Form2 frm2; // 声明一个 Form2类型的变量



/// <summary>

/// Form1构造函数

/// </summary>

public Form1()

{

InitializeComponent();

}



/// <summary>

/// Form1 加载事件 处理方法

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void Form1_Load( object sender, EventArgs e)

{

this .data = new DataClass(); // 实例化数据类

this .data.ValueChanged += new EventHandler(data_ValueChanged); // 侦听值改变事件

this .frm2 = new Form2( this .data); // 实例化Form2 类型的变量

this .frm2.Show();

}



/// <summary>

/// 值改变事件 处理方法

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void data_ValueChanged( object sender, EventArgs e)

{

this .txt1.Text = ( string )sender;

}



/// <summary>

/// btn1 单击事件 处理方法

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void btn1_Click( object sender, EventArgs e)

{

this .data.Txt = this .txt1.Text.Trim();

}

}

 

 

 Form2

   

代码
 
        
public partial class Form2 : Form

{

private DataClass data;



/// <summary>

/// Form2 默认生成的构造函数

/// </summary>

public Form2()

{

InitializeComponent();

}



/// <summary>

/// Form2 重载 构造函数

/// </summary>

public Form2(DataClass data)

{

InitializeComponent();

this .data = data;

this .data.ValueChanged += new EventHandler(data_ValueChanged); // 侦听 值改变事件

}



/// <summary>

/// 值改变事件 处理方法

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void data_ValueChanged( object sender, EventArgs e)

{

this .txt2.Text = ( string )sender;

}



/// <summary>

/// btn2 单击事件 处理方法

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void btn2_Click( object sender, EventArgs e)

{

this .data.Txt = this .txt2.Text.Trim();

}

}

 

 

 

 

其实呢,对于数据同步在.NET下还有更简单的一种处理方式,那就是“数据绑定”,并且在.NET下的大部分可视化控件都是支持数据绑定的,至于数据绑定的更多东东 请参见:
http://www.cnblogs.com/08shiyan/archive/2010/08/13/1798652.html
http://www.cnblogs.com/08shiyan/archive/2010/08/12/1797748.html

 

 


作者:誓言

博客:http://www.cnblogs.com/08shiyan

别人写的东西无论是好还是差、至少是一番心血,如有友情传播及转载请标明出处 http://www.cnblogs.com/08shiyan,谢谢。

 

 

 

转载于:https://www.cnblogs.com/08shiyan/archive/2010/10/15/1851912.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值