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

 

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

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

     

     

    窗体简单设计如下:

    父窗体 :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,谢谢。

     

     

     

posted @ 2010-10-15 16:50 把爱延续 阅读(...) 评论(...) 编辑 收藏