窗体间传值 - 上篇

下篇:传送门

经常看到有人问窗体间传值的问题 最开始我也纳闷这个问题 因为在那之前用的是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编辑添加通吃 而且代码也很简单 通常情况下 我都喜欢这样来干

这一篇篇幅够长了 剩下的在下一篇在说吧  下一篇说一下通过事件的方式来搞、、、

下篇:传送门


添加时间:2014-04-17 03:33:02 编辑时间:2016-12-02 21:58:56 阅读:3508 
常见的一些问题 C#常见问题
还没有人留言 要不你来抢一个沙发?
  • 编写评论

      我觉得区分大小写是一个码农的基本素质
[访问统计] 今天:28 总数:271342 提示:未成年人 请在大人陪同下浏览本站内容 还有:世界上最帅的码农 -> 石头 RSS:http://www.st233.com/rss Powered by -> Crystal_lz