Thứ Hai, 22 tháng 3, 2010

// // 10 comments

Trao đổi dữ liệu giữa các form

I) Giới thiệu:

Với ứng dụng WinForms, trong một số trường hợp chúng ta cần phải trao đổi dữ liệu từ form này sang form khác. Đây là vấn đề mà các coder thường gặp phải và cũng gặp nhiều lúng túng. Trong bài viết này tôi sẽ giới thiệu 4 phương pháp cơ bản và rất đơn giản. Với 4 phương pháp này hoàn toàn dựa trên những khái niệm chính trong ngôn ngữ C#:

II) Tổng quan bốn phương pháp cơ bản để passing data giữa các form:

1) Sử dụng constructor
2) Sử dụng objects
3) Sử dụng properties
4) Sử dụng delegates

Trong 4 phương pháp trên, sử dụng delegates được đánh giá cao nhất vì nó không phụ thuộc vào quá trình khởi tạo đối tượng, sự tồn tại của đối tượng. Nó chỉ đơn giản sử dụng các events do coder bẫy sẵn.

IV) Sau đây là chi tiết thực hiện từng phương pháp:

Để thực hiện các phương pháp trên:
Bước 1: Tạo một project có 2 forms (HVBK-1(Form1) và HVBK-2(Form2))

Bước 2: Với Form 1: Thêm 1 textbox và một button, sử dụng để gửi dữ liệu
Bước 3: Với Form 2: Thêm 1 Label để hiển thị dữ liệu nhận được từ Form1

Phương Pháp Constructor:
Đây là phương pháp đơn giản nhất trong 4 phương pháp. Phương pháp này sử dụng hàm dựng. Hàm dựng là hàm có đặc thù là nó được gọi đầu tiên khi ta tiến hành khởi tạo đối tượng và chỉ gọi một lần(Từ khi khởi tạo đến khi hủy đối tượng). Với phương pháp này ta chỉ cần thêm một tham biến vào hàm dựng của form2.
Code thêm tham biến vào hàm dựng của Form2


        public Form2(string strTextBox)
        {
            InitializeComponent();
            label1.Text=strTextBox;
            //Gán dữ liệu nhận được vào Label để thể hiện
        }

Tại button "Gửi dữ liệu sang form 2" ta tiến hành khởi tạo Form2 và Form2 sẽ hiện ra mỗi khi ta click vào nút này.


        private void button1_Click(object sender, System.EventArgs e)
        {
            Form2 frm = new Form2(textBox1.Text);
            frm.Show();
        }

 Kết quả: Chạy chương trình và ta có được kết quả như hình ảnh trên.

Phương Pháp Object
Object là kiểu reference và được tạo trên heap và sử dụng từ khóa new. Phương pháp này cũng rất đơn giản

Bước 1:
Tại Form1 ta tiến hành thay đổi access modifier cho textbox itừ private thành public.


    public class Form1 : System.Windows.Forms.Form {
        public System.Windows.Forms.TextBox textBox1;
        // ..............................

Tại Form2 ta tiến hành khai báo một biến frm1 có kiểu Form1



    public class Form2 : System.Windows.Forms.Form1 {
        private System.Windows.Forms.Label label1;
        public Form1 frm1;
        // ..............................

Bước 2: Tại Form1 ta tiến hành code hàm sự kiện Clicked của nút button "Gửi dữ liệu sang form 2"


    private void btnSend_Click(object sender, System.EventArgs e)
    {
        Form2 frm = new Form2();
        frm.frm1 = this;  //Gán form1 cho biến frm1 có kiểu Form1 của Form2
        frm.Show();     //Hiện Form2
    }

Bước 3: Trong hàm Load của Form2 ta tiến hành gán giá trị của ô textbox1 của form1 cho Label của form2


      private void Form2_Load(object sender, System.EventArgs e)
      {
          label1.Text = ((Form1)frm1).textBox1.Text;
      }

Kết quả: Chạy chương trình và ta có được kết quả như hình ảnh trên.

3) Sử dụng Properties:
- Properties cho phép clients truy cập trực tiếp đến các thành viên của class. Form cũng là một class, trong phương pháp này ta add thêm thuộc tính (Properties) cho mỗi form.:
- Ở Form1 ta add thêm một thuộc tính, để nhận lại giá trị từ ô textbox


    public string _textBox1 { get { return textBox1.Text; } }

- Ở Form2 ta add thêm một thuộc tính, để gán giá trị cho Label


    public string _textBox { set { label1.Text = value; } }

- Ở Form1, trong sự kiện button click ta tiến hành khởi tạo và hiển thị Form2. Giá trị của ô textbox trong Form1 sẽ được chuyền sang cho Form2 thông qua thuộc tính, và gán vào Label của Form2.



    private void button1_Click(object sender, System.EventArgs e)
    {
        Form2 frm = new Form2();
        frm._textBox = _textBox1; //gán giá trị của thuộc tính _textbox1 của Form1 cho thuộc tính _textbox của Form2
        frm.Show(); // Hiển thị Form2
    }

Kết quả được hiển thị như hình ảnh trong phần đầu đã giới thiệu.

4) Sử dụng Delegates
- Delegates là một kiểu tham chiếu (reference type), được sử dụng như là một phương thức đặc biệt(Con trỏ hàm), chúng ta có thể đăng ký bất kỳ phương thức nào với delegates. Và đây là một kỹ thuật rất được sử dụng trong lập trình sự kiện.

Bước 1: Ở Form1 ta tiến hành add một delegates như sau


public delegate void delPassData(TextBox text);


Bước 2: Trong Form2 ta tiến hành tạo một phương thức để delegate sẽ trỏ tới. Trong phương thức này ta tiến hành gán giá trị của ô textbox trong Form1 vào Label của Form2:


    public void funData(TextBox txtForm1) { label1.Text = txtForm1.Text; }


Bước 3: Trong sự kiện button click của form1 ta tiến hành khởi tạo Form2 và delegate. Chỉ ra một phương thức của Form2 và tiến hành gọi delegate như sau:


    private void btnSend_Click(object sender, System.EventArgs e)
    {
        Form2 frm = new Form2();
        delPassData del = new delPassData(frm.funData);
        del(this.textBox1);
        frm.Show();
    }

Kết quả được thể hiện như hình ảnh ở phần đầu tiên.

Trong 4 phương pháp này, phương pháp sử dụng hàm dựng (Constructor) được đánh giá là kém nhất, vì đối tượng chỉ được khởi tạo một lần, nếu đối tượng ko được hủy(form2 không hủy hoặc tắt đi) mà ta lại muốn thay đổi dữ liệu chuyền từ form1 sang form2 thì phương pháp này ko thực hiện được. Delegate là phương pháp khắc phục rất tốt nhược điểm này.

Bài hướng dẫn này bên: học viện bách khoa.

10 comments:

Bin nói...

Rất hay, cám ơn anh nhìu nhìu nha, em đang làm tiểu luận, muốn nó hiện 1 cái label tên mà mình vừa đánh ở textbox, khi mình đăng nhập, giống như kiểu lưu cookie của web đó. Cám ơn rất nhìu !

Denis nói...

Mình có một vấn đề mọi người giúp mình với nhé!


Mình có 2 form:
form1:có 1 combobox chứa tên loại sản phẩm, 1 textbox cho nhập tên sản phẩm và một nút lưu.
form2: có 2 textbox để nhập dữ liệu vào và nút thêm loại sản phẩm và một nút trở lại.

Khi mình chọn dòng --thêm mới-- trong combobox trong form1 thì nó sẽ hiện ra form2 dưới dạng showdialog, mình sẽ thêm loại sản phẩm vào form2 và nhấn nút Thêm sau đó nhấn nút trở về.
Thì loại sản phẩm vừa thêm sẽ được cập nhật lại combobox ở form1 mà khỏi cần tắt form1 và mở lại.

Bạn chỉ mình cách dùng delegate hay cách nào dễ nhất để truyền dữ liệu từ form2 sang form1 với, mình đang rất cần ,nếu được bạn chỉ mình chi tiết nhé!

Thanks!

Unknown nói...

@Denis
Chào bạn, mình nhận thấy những yêu cầu của bạn đưa ra khá thực tế. Nhưng thực sự chưa tiện ích cho người sử dụng lắm khi để thêm mới trong combox. Theo như y.cầu thì textbox & nút lưu trên form1 sẽ không tham giá vào quá trình trao đổi dữ liệu giữa 2 form.

Nếu dùng ShowDialog() thì đơn giản ta chỉ cần sử dụng phương pháp thứ 3 theo trên là được và đơn giản hơn nếu bạn chưa thạo dùng delegate.
Bạn có thể làm như dưới đây theo 2 bước, chúc bạn thành công:

1. Tại Form2 Định các thuộc tính, và sự kiện khi người dùng click vào nút: Thêm

        /// Dữ liệu hoặc thông tin cần truyền cho form1
        private string m_str_data;
        /// Thuộc tính chỉ đọc để cho các lớp khác gọi
        public string NewData
        {
            get { return m_str_data; }
        }

        private void btnThemMoi_Click(object sender, EventArgs e)
        {
            try
            {
                // 1. Gán dữ liệu, tùy vào từng bài toán
                this.m_str_data = "Thu tập các dữ liệu, gán cho this.m_str_data";
                // 2. Lưu vào cơ sở dữ liệu
                // this.SaveDatabase();
                // 3. Nếu thành công, thì đóng form lại
                this.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

2. Tại Form1 xử lí sự kiện khi người dùng chọn Combox tại mục: -- Thêm mới --

        private void cboSanPham_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                // Giả sử item thứ 1 của combox là: -- Thêm mới --
                if (this.cboSanPham.SelectedIndex == 0)
                {
                    var form2 = new Form2();
                    form2.ShowDialog();

                    if (form2 != null && form2.NewData != null)
                    {
                        MessageBox.Show(form2.NewData);
                        this.cboSanPham.Items.Add(form2.NewData);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

Denis nói...

Thanks bạn rất nhiều, mình sẽ thử ý kiến của bạn xem sao!

Unknown nói...

Cách làm của bạn Vũ Như Bảo đúng cái mình cần, cám ơn bạn rất nhiều

Unknown nói...

mình đang gặp vấn đề về phần này, mọi người xem giúp mình một chút.
mình có 2 form:
from1: có 3 textBox nhập mã chỉ số sử dụng, nhập chỉ số cũ, chỉ số mới.
from2: có 1 combobox chọn mã chỉ số sử dụng, 2 texbox để nhập chỉ số cũ chỉ số mới, 1 texbox để nhập điện năng tiêu thụ, 1 button Tính
mình muốn ở from2: khi chọn mã chỉ số sử dụng nó sẽ laod luôn chỉ số cũ và chỉ số mới ở from 1 lên from 2 để thực hiện tính điện năng tiêu thụ
Các bạn xem giúp mình với. Mình đang làm thực tập về phần này mà chưa biết xử lý như thế nào.

Unknown nói...

@Thùy dương:
Bạn tham khảo cách 2) Phương Pháp Object
Cách này đáp ứng được yêu cầu của bạn !

Unknown nói...

Cho mình hỏi là
Khi mình đăng nhập vào bằng tài khoản nào thì chỉ thực hiện các thao tác là chỉ vs tài khoản đăng nhập zậy

Unknown nói...

Cảm ơn rất nhiểu !

Unknown nói...


delPassData del = new delPassData(frm.funData);
del(this.textBox1);
giải thích giúp em cú pháp bên trên với ạ