在写winform的过程中,我们经常遇到需要窗体间传值。今天在此总结一下,分享给各位。
窗体间传值有几种情况:
1、一个项目内(指的是在解决方案管理器中的同一个项目,如下图)
2、在另一个项目或类库中调用窗体的事件或方法,或改变窗体的某个状态,总之,你需要在另一个项目或类库中改变另一个窗体中的一些东西,而这两个不在同一个项目下,如下图:
3、在另一个项目中调用窗体中的方法,但与 2 不同的事,他们在不同的线程中,当前本例不会取消控件的安全检查。
=============================解决方法==============================================
下面介绍了本人认为的应对这三种情况最好的方法。
第一种情况很简单:以同一个项目中的一个类库 改变窗体中TextBox的值为例。
第一步 在这个项目中新建一个类库 Helper,添加一个公用的方法SetTextBox
其中 FormMain 为当前窗体的类型
第二步 在窗体中定义一个公共的方法,在这个方法内改变TextBox的值:
第三步 在窗体中增加一个按钮Button1,当按钮点击的时候调用类库中的方法改变窗体中TextBox的值
全部代码:
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Text; 7 using System.Windows.Forms; 8 9 namespace Win10 {11 public partial class FormMain : Form12 {13 14 public FormMain()15 {16 InitializeComponent();17 }18 19 private void button1_Click(object sender, EventArgs e)20 {21 Helper h = new Helper();22 h.SetTextBox(this);23 }24 public void SetValue(string text)25 {26 this.textBox1.Text = text;27 }28 }29 }
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 5 namespace Win 6 { 7 public class Helper 8 { 9 public void SetTextBox(FormMain f)10 {11 f.SetTextValue("通过类库改变窗体中TextBox的值");12 }13 }14 }
**********************************************************************************************************************************************
第二种情况
当遇到第二种情况是再用第一种情况已经不可以了,因为窗体肯定要引用类库,而类库不能引用窗体(否则会vs就会告诉你循环引用了,神马?循环引用都不知道?自己去找解释吧)
这时候就应该请出 委托 大神了。
本例还是模拟上一次操作,只不过是在类库中调用方法改变窗体中的某个值。
第一步,在窗体中引用类库。
第二部,在类库中增加一个类 DEL,此类专门用于存储委托(本人习惯,也可以放到其他类文件中,但不能包含在类中)
1 using System;2 using System.Collections.Generic;3 using System.Text;4 5 namespace Win.Lib6 {7 public delegate void DelSetTextValue(string text);8 }
第三步:在类库中再增加一个类 Helper(第一个实例中的Helper本人已删除,避免重名后还要写命名空间)
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 5 namespace Win.Lib 6 { 7 public class Helper 8 { 9 public void SetFormTextValue(DelSetTextValue setValue)10 {11 setValue("在类库中调用窗体中的方法");12 }13 }14 }
第四步:窗体中的方法,一共有两个,第一个是类库中调用的方法,第二个是要调用类库的方法
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Text; 7 using System.Windows.Forms; 8 using Win.Lib; 9 10 namespace Win11 {12 public partial class FormMain : Form13 {14 public FormMain()15 {16 InitializeComponent();17 }18 19 public void SetTextValue(string text)20 {21 this.textBox1.Text = text;22 }23 24 private void button1_Click(object sender, EventArgs e)25 {26 Helper h = new Helper();27 h.SetFormTextValue(SetTextValue);28 }29 }30 }
至此,第二个实例完成。
但这个有个弊端,就是当使用多线程的时候,无法调用,原因有二:
一:多线程有对量安全性检查,非本线程创建的控件其它线程不能访问,当然你可以去掉控件的安全性检查,但这样会不安全。
二:由于多线程只能传一个object参数,无法调用窗体中的多个方法。
带着这些问题,请看实例三。
***************************************************************************************************************************************************
实例三: 在多线程中,类库调用窗体中的多个方法(改变多个控件的值或属性)
与实例二大同小异,由于代码上有注释,直接上代码了。
using System;using System.Collections.Generic;using System.Text;namespace Win.Lib{ public delegate void DelSetTextValue(string text); public class ThreadModel { public DelSetTextValue SetLblValue { get; set; } public DelSetTextValue SetTextValue { get; set; } }}
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 5 namespace Win.Lib 6 { 7 public class Helper 8 { 9 public void ChangeFormValue(object obj)10 {11 //将obj拆箱为ThreadModel类型12 ThreadModel tm = obj as ThreadModel;13 tm.SetLblValue("异线程调用窗体中的方法_Lbl");14 tm.SetTextValue("异线程调用窗体中的方法_Text");15 }16 }17 }
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Text; 7 using System.Windows.Forms; 8 using System.Threading; 9 using Win.Lib;10 11 namespace Win12 {13 public partial class FormMain : Form14 {15 16 public FormMain()17 {18 InitializeComponent();19 }20 21 void SetTextValue(string text)22 {23 if (InvokeRequired)24 {25 Invoke(new DelSetTextValue(SetTextValue), text);26 }27 else28 {29 this.textBox1.Text = text;30 }31 }32 33 void SetLblValue(string text)34 {35 if (InvokeRequired)36 {37 Invoke(new DelSetTextValue(SetLblValue),text);38 }39 else40 {41 this.label1.Text = text;42 }43 44 }45 46 private void button1_Click(object sender, EventArgs e)47 {48 Helper h = new Helper();49 Thread t = new Thread(h.ChangeFormValue);50 t.IsBackground = true;51 52 //声明一个更新末班变量,并赋值53 ThreadModel tm = new ThreadModel();54 tm.SetLblValue = SetLblValue;55 tm.SetTextValue = SetTextValue;56 57 //将tm封装为一个变量传给ChangeFormValue方法58 t.Start(tm);59 }60 }61 }
本人才疏学浅,在此分享思路为抛砖引玉,大家有不同的思路可以分享,让每个人都成为优秀的程序员。
如发现代码有问题,请回复。