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


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

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

      窗体简单设计如下:

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



    返回导读目录,阅读更多随笔



    分割线,以下为博客签名:

    软件臭虫情未了
    • 编码一分钟
    • 测试十年功


    随笔如有错误或不恰当之处、为希望不误导他人,望大侠们给予批评指正。

  • 相关阅读:
    iOS_UIImage的方向(imageOrientation)
    iOS-LaunchImage启动页
    iOS_UIImage_毛玻璃效果
    iOS_常用C语言函数
    iOS_UIImage_Gif的合成
    iOS_UIImage_Gif的分解
    iOS_UIImge_Gif的展示
    iOS_UIImage_jpg<-->png转换
    Mysql学习第三天
    Mysql学习第二天
  • 原文地址:https://www.cnblogs.com/08shiyan/p/1851912.html
Copyright © 2020-2023  润新知