下篇:传送门
经常看到有人问窗体间传值的问题 最开始我也纳闷这个问题 因为在那之前用的是vb6(我很垃圾的)要取某个控件的信息直接可以通过窗体打点 然后点出东西来 然后我在C#中发现这样做貌似不行(那个时候压根就不怎么明白面向对象什么new之内的) 然后就特郁闷到处百度 然后发现通过构造器把参数传递过去 然后在Form2中用一个全局变量接受 那个时候看着代码半天没理解过来是啥意思 因为那个时候 脑子里面不懂面向对象
说这么多的意思是 通常情况下 问这样问题的人都是才接触不久的人 如果你也一点不懂什么叫做 面向对象 的话 那还是建议去了解一下吧 不然感觉会很抽象
那么我列举一些遇到或者看到别人遇到过的一些情况 然后说说一些我的解决思路 然后自己参考吧
话不多说 先来看看第一种直接通过构造器传值 先来说说需求:
我希望得到的效果是点击get按钮的时候 把Form1里面文本框的值显示到Form2的文本框中 那么此时我可以直接把Form1中的文本框直接给Form2 这样能在Form2中直接操作Form1中的文本框 那么在Form2中代码可以这样写:
public partial class Form2 : Form { //从构造器中接收一个TextBox public Form2(TextBox tbx) { InitializeComponent(); //将接收到的TextBox赋值给类里面的全局的一个变量 m_form1_tbx = tbx; } private TextBox m_form1_tbx; private void button1_Click(object sender, EventArgs e) { //操作m_form1_tbx就等同于操作Form1中的TextBox1因为传过来的就是他 textBox1.Text = m_form1_tbx.Text; } }写了注释了 不用解释了 然后在Form1中:
new Form2(textBox1).Show();直接就把textBox1给Form2 然后在Form2中就可以向操作自己的TextBox那样 效果如下:
当然这里是只有一个文本框的情况 如果说在Form1中有好几个文本框在Form2中都要用到 那是不是同样可以通过构造器把TextBox传递过去? 当然你可以那么干 一两个倒好 几十百八个 你构造器也接收几十个么?显然不科学 当然你可以传递一个TextBox[]数组过去 不过你还可以这样 直接把Form1给Form2 那么刚才在Form2中的代码就要改一下了:
public partial class Form2 : Form { //从构造器中接收一个Form1 public Form2(Form1 frm) { InitializeComponent(); //将接收到的Form1复制给类里面的全局的一个变量 m_frm1 = frm; } private Form1 m_frm1; private void button1_Click(object sender, EventArgs e) { //操作m_frm就等同于操作Form1 textBox1.Text = m_frm1.textBox1.Text; } }然后Form1中:
new Form2(this).Show();不过注意 这里你可能发现问题了 在m_frm1..点..点点点..我点点点点点....随便你怎么点都点不出textBox1来 是的的确是那样的不是bug、因为textBox1对于Form1来说本来就是私有的(private)所以你还要干一件事情把它变成公开的:
找到自动生成的代码 将private改成public
这样的好处就是 只需要传一个this过去 在Form2中可以直接获取到在Form1中的任意控件 只要你把控件改成public
最开始我也是这么干的 可是到了后来我觉得不太爽 因为我总是感觉把private改成了public很别扭 所以我不想去改 但是如果不改我又访问不到 然后我就直接吧TextBox封装成属性去访问让后在Form1中的代码就变成了这样:
public partial class Form1 : Form { public Form1() { InitializeComponent(); } public TextBox Tbx1 { get { return this.textBox1; } } private void Form1_Load(object sender, EventArgs e) { new Form2(this).Show(); } }通过Tbx1属性返回textBox1这样 就不用去把textBox1的private改成public了
不过在Form2中的button1_Click里面就点不出textBox1了但有个Tbx1;
private void button1_Click(object sender, EventArgs e) { textBox1.Text = m_frm1.Tbx1.Text; }
如果你不希望把Form1通过构造器传过去了 那么可以通过Owner属性把Form1给Form2 那么Form1中:
new Form2() { Owner = this }.Show(); //Form2 frm2 = new Form2(); //frm2.Owner = this; //frm2.Show();上面是简便的写法然后 Form2构造器也不需要参数了 一切该怎么怎么地 然后在Form2中的button1_Click中:
private void button1_Click(object sender, EventArgs e) { textBox1.Text = ((Form1)this.Owner).Tbx1.Text; }不过注意:如果没有在Form1中没有给new出来的Form2的Owner赋值的话 那么这个值是null 还有设置了Owner的话 那么Form2将会置前于Form1显示 也就是说当Form1在Form2背后的时候 你怎么点击Form1他都不会跳到Form2前面显示
以前我还不知道封装属性的时候 还用过这样的方式 在Form1中写一个public的方法 方法返回textBox1的值 其实也差不多就是封装一个意思
现在来说说另一种情况 很多时候Form2对于Form1来说估计就是一个模态(不要说你不知道啥是模态窗口ShowDialog)窗口用来编辑数据之类的 比如:
当我点击Form1的edit的时候弹出模态对话框Form2来编辑值 当然这里可以通过上面的方式来完成 先来看看上面方式的代码:
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { new Form2(textBox1).ShowDialog(); } }Form2:
public partial class Form2 : Form { public Form2(TextBox tbx) { InitializeComponent(); m_tbx = tbx; textBox1.Text = tbx.Text;//将值显示出来 } private TextBox m_tbx; private void button1_Click(object sender, EventArgs e) { m_tbx.Text = textBox1.Text; this.Close(); } }代码很简单不过多做解释我现在想说的是下面这一种方式 直接上代码在解释 Form1:
private void button1_Click(object sender, EventArgs e) { Form2 frm2 = new Form2(textBox1.Text);//注意 这里是Text而不是控件 if (frm2.ShowDialog() == DialogResult.OK) { textBox1.Text = frm2.ResultString; } }Form2:
public partial class Form2 : Form { public Form2(string str) { InitializeComponent(); textBox1.Text = str;//显示出来 } public string ResultString { get { return textBox1.Text; } } private void button1_Click(object sender, EventArgs e) { //这里可以不用Close对于模态对话框而言 当给DialogResult赋值的时候 //窗体会自己关闭的 所以后面不用this.Close() this.DialogResult = System.Windows.Forms.DialogResult.OK; } }对于模态对话这种 我目前而言最喜欢的就是这样的方式首先Form2中接收一个将要被编辑的字符串 然后提供了一个ResultString属性用来返回Form2中textBox1的值 但是你看到button1_Click里面感觉好像是Form2啥事也没有做 的确是这样的Form2只是负责提供一个窗体出来编辑数据而已 完了直接关掉不修改原来Form1中的textBox1 而修改的过程放到了Form1中 在Form1中判断模态对话框的返回值 如果是Ok(你要想啥值 你自己统一)那就表示 用户确实要修改数据而不是直接关闭了窗体 或者点击了取消按钮之内的(这里为了节省文章篇幅 减少代码量 就只有ok按钮) 这种方式很方便的 对于Form2而言 把所有的数据都用属性保存下来 完事就关窗体 由Form1上面得到Form2的DialogResult返回值决定要不要真的修改数据 如果要数据全部在Form2的属性中自己取 爱怎么取怎么取Form2不用管、、
这里来一个实用的例子 比如我有这样一个需求:
Form1上是展示的假设是Student信息 而右边的窗体则可能是编辑或者添加信息的 首先需要一个Stuent类:
public class Student { private string _Name; public string Name { get { return _Name; } set { _Name = value; } } private int _Age; public int Age { get { return _Age; } set { _Age = value; } } public override string ToString() { return string.Format("Name:{0} -- Age:{1}", this._Name, this.Age); } }这个不做解释 然后是来看看右边的窗体的代码:
public partial class Form3 : Form { public Form3(Student stu) { InitializeComponent(); this._Student = stu; this.BindControl(stu); this.btn_cancel.Click += (s, e) => this.Close(); } private Student _Student; public Student Student { get { return _Student; } } private void BindControl(Student stu) { if (stu == null) {//如果null表示添加一个学生 this.Text = "Add"; return; } else { this.Text = "Edit"; } this.tbx_name.Text = stu.Name; this.tbx_age.Text = stu.Age.ToString(); } private void btn_ok_Click(object sender, EventArgs e) { if (this._Student == null) this._Student = new Student(); this._Student.Name = tbx_name.Text; this._Student.Age = int.Parse(tbx_age.Text); this.DialogResult = DialogResult.OK; } }窗体直接接收一个学生类 然后给窗体上面的_Student属性 然后去调用BindControl去绑定控件显示 如果是null那么表示要添加一个Student否则就是编辑一个Student ok按钮代码也不用做什么解释了 不过数据的有效性要在里面验证一下 这里没有 为了代码少点 自己写的时候注意就行了 然后来看看Form1上面 两个菜单的代码:
private void addToolStripMenuItem_Click(object sender, EventArgs e) {//添加一个学生 Form3 frm3 = new Form3(null); if (frm3.ShowDialog() == DialogResult.OK) { listBox1.Items.Add(frm3.Student); } } private void editToolStripMenuItem_Click(object sender, EventArgs e) {//编辑一个学生 if (listBox1.SelectedIndex == -1) return; Form3 frm3 = new Form3((Student)listBox1.Items[listBox1.SelectedIndex]); if (frm3.ShowDialog() == DialogResult.OK) { listBox1.Items[listBox1.SelectedIndex] = frm3.Student; } }
上面的是添加的 构造的时候传一个null进去表示窗体是用来添加的 下面的把选中的Student传给了Form3当Form3得到的是一个有效的Student的时候就会把数据绑定到窗体上去 这样一来Form3编辑添加通吃 而且代码也很简单 通常情况下 我都喜欢这样来干
这一篇篇幅够长了 剩下的在下一篇在说吧 下一篇说一下通过事件的方式来搞、、、
下篇:传送门