none
vb2008 請問我有兩張表單,表單2和表單3相互傳值要怎麼做 RRS feed

  • 問題

  • 各位大大有1個問題請教各位:研究了一下午都試不出個所以然來
     
    問題1.我有一個主表單,主表單內有一個Form2的表單,在Form2的表單上有一個Button及Textbox,當我按下按下Button時會呼叫Form3的表單,在Form3有個DataGridView它連接資料庫從資料庫取值。當我點選DataGridView某一列時會將資料傳到表單2的Textbox.text,請問程式碼要怎麼寫?還有為何我在Form3的DataGridView無法取值但把相同程試碼放在Form2 再建一個DataGridView在Form2就可接到資料庫值問題到底在那呢?可否請教各位大大這個程式該如何寫?
    2009年11月21日 上午 09:07

解答

  • 其實以上各位前輩寫的都是解答.因為這個問題個解法其實還多種的. 不過重點是如何讓兩個不同的表單知道對方存在, 並且能夠存取對方的成員.
    關鍵在於當我們在寫Form1, Form2的程式時, 他們並不是執行個體, 而是我們在設計Form1與Form2這兩個類別.而在執行階段存取的卻是他們的執行個體 (靜態成員例外).
    而在VB2005以後為了讓過去VB6.0的使用者更容易適應使用VB.NET的表單, 所以在Form類別的使用上做了一些更動, 例如:我們會直接在VB.NET上用 Form2.Show(), 但是在C#上這樣是不行的.C#上必須遵照規定先宣告並產生執行個體才能使用該執行個體的Show()方法. 而在VB.NET上卻沒有這樣做 (過去使用VB2003也不能直接使用Form2.Show()).就是這一點很容易讓寫VB.NET的人觀念混淆.
    說了這麼多,其實就是在觀念上要把類別和執行個體的觀念分清楚.否則當你要在一堆不同類別產生的執行個體傳遞參數就會混淆.
    在這邊我也貢獻一種寫法, 主要是使用BindingSource類別來達成同步化.
    Public Class Form1
        Private myBindingSource As New BindingSource
        Public Property Form1BindingSource() As BindingSource
            '自訂屬性1:用於存取 Form1 類別所產生執行個體的 myBindingSource
            Get
                Return myBindingSource
            End Get
            Set(ByVal value As BindingSource)
                myBindingSource = value
            End Set
        End Property
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim frm2 As New Form2
            frm2._myFirstForm = Me
            myBindingSource = frm2._myBindingSource
            frm2.Show()
            TextBox1.DataBindings.Add("Text", myBindingSource, "Col1")
        End Sub
    End Class

    Public Class Form2
        Private myDatatable As New DataTable
        Private myBindingSource As New BindingSource
        Public Property _myBindingSource() As BindingSource
            '自訂屬性1:用於存取 Form2 類別所產生執行個體的 myBindingSource
            Get
                Return myBindingSource
            End Get
            Set(ByVal value As BindingSource)
                myBindingSource = value
            End Set
        End Property
        Private myFisrtForm As Form1
        Public Property _myFirstForm() As Form1
            '自訂屬性2: 用於讓呼叫產生Form2 類別執行個體的執行個體傳遞自己的參考指標過來(這個例子是Form1)
            Get
                Return myFisrtForm
            End Get
            Set(ByVal value As Form1)
                myFisrtForm = value
            End Set
        End Property
        Private Sub Form2_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
            myFisrtForm.TextBox1.DataBindings.Clear()
            myFisrtForm.Form1BindingSource = Nothing
        End Sub
        Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            myDatatable.Columns.Add("Col1")
            myDatatable.Columns.Add("Col2")
            RowsAdd(myDatatable)
            myBindingSource.DataSource = myDatatable
            DataGridView1.DataSource = myBindingSource
        End Sub
        Private Sub RowsAdd(ByVal myDatatable As DataTable)
            '這個只是為了產生資料給myDataTable執行個體
            Dim i As Integer
            For i = 0 To 9
                Dim myNewRow As DataRow = myDatatable.NewRow
                myNewRow.Item(0) = i
                myNewRow.Item(1) = Chr(65 + i)
                myDatatable.Rows.Add(myNewRow)
            Next
        End Sub
    End Class

    關於兩個表單傳值, 你可以參考研讀一下蹂躪大部落格上的一篇文章 http://www.dotblogs.com.tw/larrynung/archive/2009/03/24/7669.aspx
    BindindSource的部份,  可以看以下兩篇
    http://www.dotblogs.com.tw/billchung/archive/2009/06/15/8836.aspx
    http://www.dotblogs.com.tw/billchung/archive/2009/06/19/8903.aspx





    學而不思則罔, 思而不學則殆.
    如果你一直都看不懂、不想學習看懂、抗拒看懂MSDN Library的話,那你最好放棄想要寫好程式這件事
    如果你自私地不肯回饋與分享,那別人為何要花時間回答你的問題?
    • 已標示為解答 MichaelTsai10 2009年11月23日 上午 06:12
    2009年11月22日 上午 02:44
    版主
  •  Private Sub Form2a_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Dim Ys As New SqlDataAdapter("SELECT CusAcc FROM PURCU ", strDbCon)
            Ys.Fill(c2, "PURCU")
     
      這行沒有發生例外嗎?, 本想說若有發生例外的話可能是 c2 沒有 As New DataSet 的關係...
    Public Class Form2a
        Friend f2 As Form2
        Dim strDbCon As String
        Dim c2 As DataSet
    請試試看下列是否可行:

        Private Sub Form2a_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Dim Ys As New SqlDataAdapter("SELECT CusAcc FROM PURCU ", strDbCon)
    
            c2 = New DataSet
            Ys.Fill(c2, "PURCU")
    
            Dim Yg As DataTable = c2.Tables("PURCU")
            DataGridView1.DataSource = Yg
    
            f2.SetText(DataGridView1.CurrentCell.Value)
        End Sub
    • 已標示為解答 MichaelTsai10 2009年11月23日 上午 06:11
    2009年11月23日 上午 04:37

所有回覆

  • 張貼文章應注意事項及應提供資訊

    請把目前的程式貼出來,並加以說明,參考置頂說明...
    2009年11月21日 上午 10:55
  • http://social.msdn.microsoft.com/forums/zh-TW/232/thread/10b3b66e-2320-4c8c-b8c9-1c34fd03bdd5/
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    提問時,錯誤情境描述與錯誤訊息很重要,情境描述包含你做了什麼,預期的結果與實際發生的結果。一個最爛的問法範例:「我的電腦電腦怎麼不能開機?」誰知道你家是不是沒電還是你根本找不到電源鈕。
    2009年11月21日 上午 10:57
  • 各位大大:
           Form2的部份就寫這樣
    Public Class Form2
        Inherits System.Windows.Forms.Form
        Dim myForm3 As Form3

        Private Sub Button1_Click(ByVal sender As System.Object, _
                ByVal e As System.EventArgs) Handles Button1.Click
            myForm3 = New Form3()
            myForm3.Show()
      End Sub

    End Class
          
           Form3的部份就寫這樣
    Imports System
    Imports System.Collections.Generic
    Imports System.ComponentModel
    Imports System.Data
    Imports System.Drawing
    Imports System.Linq
    Imports System.Text
    Imports System.Windows.Forms
    Imports System.Data.SqlClient
    Imports System.Windows
    Public Class Form3

        Private Sub Form3_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    1      Dim conn As SqlConnection
    2      Dim strDbCon As String
    3      strDbCon = "Persist Security Info=False;User ID=sa;pwd=sa;Initial Catalog=BUYER;Data 
    4      Source=192.168.1.200"
    5      conn = New SqlConnection(strDbCon)
    6      conn.Open()
    7      Dim Ys As New SqlDataAdapter("SELECT UserName  FROM PURCU ", strDbCon)
    8      Ys.Fill(a2, "PURCU")
    6      Dim Yg As New DataTable
    7      Yg = a2.Tables("PURCU")
    8      DataGridView1.DataSource = Yg
    9  End Sub
    End Class

    我要把From3 在DataGridView1中選到的值傳回Form2裡的Textbox1但不知怎麼寫 書上也沒寫 找了大半天 試了大半天也沒結果所以只好用敘述。所以請各位大大原諒囉

    2009年11月21日 下午 01:06
  • 您可以這樣做:

    1) Form2類別

    Public Class Form2
        Inherits System.Windows.Forms.Form
        Dim myForm3 As Form3

        Private Sub Button1_Click(ByVal sender As System.Object, _
                ByVal e As System.EventArgs) Handles Button1.Click
            myForm3 = New Form3()
            myForm3.f2=Me
            myForm3.Show()
        End Sub

        Friend Sub SetText(ByVal data As String)
            TextBox1.Text=data
        End Sub
    End Class

    2) Form3類別

    Public Class Form3

        Friend f2 As Form2  

        Private Sub Form3_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            f2.SetText(DataGridView1.CurrentCell.Value)
        End Sub
    End Class

    2009年11月21日 下午 01:40
  • Hi,

    問題一, < 點選DataGridView某一列時會將資料傳到表單2的Textbox.text >
    多種方式, 例如:
    1) 在 Form3 的 DataGridView 的 CellContentClick 事件, 將表單2的 Textbox.text = DataGridView1.Rows(e.RowIndex).Cells(0).Value.ToString (依您 Select SQL 看, Cells(0)就是 UserName 欄).

    2) 用全域變數供各表單存取.

    3) 如心冷熱情熄大(不敢簡稱心大或心冷大)提示的資訊, 璉璉大的說明. 這方式我之前從沒發現, 受教了, 托福托福.

    4) 如this大的範例, (放在 Form3 Load 事件是否是筆誤?)這方式我之前從沒想過, (上述方法 1 還要多避開 e.RowIndex <0 的情況). 再受教了, 托福托福.

    問題二, < 還有為何我在Form3的DataGridView無法取值但把相同程試碼放在Form2 再建一個DataGridView在Form2就可接到資料庫 >
    多種可能, 例如:
    猜: a2 是不是宣告在 Form2 內, 若是, 可以把 a2 放在 Module public宣告成全域變數.
    若想保留在 Form2 內, 先宣告成 public, Form3 內就要用 Ys.Fill(Form2.a2, "PURCU").

    2009年11月21日 下午 03:37
  • 引用那篇的重點在 Form.DialogResult

    以此為關鍵字查線上手冊:

    使用者輸入到對話方塊
    ms-help://MS.MSDNQTR.v90.cht/dv_mancli/html/63ad8645-6842-45e8-b215-73f778e29a55.htm

    HOW TO:在設計階段建立對話方塊
    ms-help://MS.MSDNQTR.v90.cht/dv_mancli/html/c165e430-a9dc-4fec-acb7-f4835c36f799.htm

    HOW TO:擷取對話方塊的結果
    ms-help://MS.MSDNQTR.v90.cht/dv_mancli/html/69df2b70-5f60-4273-bf80-557392e0a50e.htm

    HOW TO:關閉對話方塊並保留使用者輸入
    ms-help://MS.MSDNQTR.v90.cht/dv_mancli/html/9e118fad-3bf4-4f70-a3de-a0cda2b0229d.htm



    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    提問時,錯誤情境描述與錯誤訊息很重要,情境描述包含你做了什麼,預期的結果與實際發生的結果。一個最爛的問法範例:「我的電腦電腦怎麼不能開機?」誰知道你家是不是沒電還是你根本找不到電源鈕。
    2009年11月21日 下午 03:49
  • 親愛的各位大大:對此問題一直得不到完整的解答也試了很久(現在還在試)是否可以寫個完整的程式碼呢?不請之請尚請海涵。
    2009年11月21日 下午 04:39
  • Ys.Fill(a2, "PURCU")

    http://2008skydrive.spaces.live.com/

    您的問題有幾個?tihs大的範例,應該可解決大部份;樓上所言,a2 DataSet,您是在哪宣告的?您要把程式壓縮放在SkyDrive等網路空間嗎...
    2009年11月22日 上午 01:23
  • 其實以上各位前輩寫的都是解答.因為這個問題個解法其實還多種的. 不過重點是如何讓兩個不同的表單知道對方存在, 並且能夠存取對方的成員.
    關鍵在於當我們在寫Form1, Form2的程式時, 他們並不是執行個體, 而是我們在設計Form1與Form2這兩個類別.而在執行階段存取的卻是他們的執行個體 (靜態成員例外).
    而在VB2005以後為了讓過去VB6.0的使用者更容易適應使用VB.NET的表單, 所以在Form類別的使用上做了一些更動, 例如:我們會直接在VB.NET上用 Form2.Show(), 但是在C#上這樣是不行的.C#上必須遵照規定先宣告並產生執行個體才能使用該執行個體的Show()方法. 而在VB.NET上卻沒有這樣做 (過去使用VB2003也不能直接使用Form2.Show()).就是這一點很容易讓寫VB.NET的人觀念混淆.
    說了這麼多,其實就是在觀念上要把類別和執行個體的觀念分清楚.否則當你要在一堆不同類別產生的執行個體傳遞參數就會混淆.
    在這邊我也貢獻一種寫法, 主要是使用BindingSource類別來達成同步化.
    Public Class Form1
        Private myBindingSource As New BindingSource
        Public Property Form1BindingSource() As BindingSource
            '自訂屬性1:用於存取 Form1 類別所產生執行個體的 myBindingSource
            Get
                Return myBindingSource
            End Get
            Set(ByVal value As BindingSource)
                myBindingSource = value
            End Set
        End Property
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim frm2 As New Form2
            frm2._myFirstForm = Me
            myBindingSource = frm2._myBindingSource
            frm2.Show()
            TextBox1.DataBindings.Add("Text", myBindingSource, "Col1")
        End Sub
    End Class

    Public Class Form2
        Private myDatatable As New DataTable
        Private myBindingSource As New BindingSource
        Public Property _myBindingSource() As BindingSource
            '自訂屬性1:用於存取 Form2 類別所產生執行個體的 myBindingSource
            Get
                Return myBindingSource
            End Get
            Set(ByVal value As BindingSource)
                myBindingSource = value
            End Set
        End Property
        Private myFisrtForm As Form1
        Public Property _myFirstForm() As Form1
            '自訂屬性2: 用於讓呼叫產生Form2 類別執行個體的執行個體傳遞自己的參考指標過來(這個例子是Form1)
            Get
                Return myFisrtForm
            End Get
            Set(ByVal value As Form1)
                myFisrtForm = value
            End Set
        End Property
        Private Sub Form2_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
            myFisrtForm.TextBox1.DataBindings.Clear()
            myFisrtForm.Form1BindingSource = Nothing
        End Sub
        Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            myDatatable.Columns.Add("Col1")
            myDatatable.Columns.Add("Col2")
            RowsAdd(myDatatable)
            myBindingSource.DataSource = myDatatable
            DataGridView1.DataSource = myBindingSource
        End Sub
        Private Sub RowsAdd(ByVal myDatatable As DataTable)
            '這個只是為了產生資料給myDataTable執行個體
            Dim i As Integer
            For i = 0 To 9
                Dim myNewRow As DataRow = myDatatable.NewRow
                myNewRow.Item(0) = i
                myNewRow.Item(1) = Chr(65 + i)
                myDatatable.Rows.Add(myNewRow)
            Next
        End Sub
    End Class

    關於兩個表單傳值, 你可以參考研讀一下蹂躪大部落格上的一篇文章 http://www.dotblogs.com.tw/larrynung/archive/2009/03/24/7669.aspx
    BindindSource的部份,  可以看以下兩篇
    http://www.dotblogs.com.tw/billchung/archive/2009/06/15/8836.aspx
    http://www.dotblogs.com.tw/billchung/archive/2009/06/19/8903.aspx





    學而不思則罔, 思而不學則殆.
    如果你一直都看不懂、不想學習看懂、抗拒看懂MSDN Library的話,那你最好放棄想要寫好程式這件事
    如果你自私地不肯回饋與分享,那別人為何要花時間回答你的問題?
    • 已標示為解答 MichaelTsai10 2009年11月23日 上午 06:12
    2009年11月22日 上午 02:44
    版主
  • 親愛的This大大 我嘗試你的寫法去作但是發現有點問題,可能是我設定錯誤或者天資愚昧請指教一下

    Fom2部份:

         Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Dim conn As SqlConnection
            Dim strDbCon As String
            Dim ds, a1 As New DataSet
            Dim myDatatable1 As New DataTable
            strDbCon = "Persist Security Info=False;User ID=sa;pwd=sa;Initial Catalog=BUYER;Data Source=192.195.68.50"
            conn = New SqlConnection(strDbCon)
            conn.Open()
            Dim bs As New SqlDataAdapter("SELECT * FROM PUREM ", strDbCon)
            bs.Fill(ds, "PUREM")
            Dim yy As New DataTable
            yy = ds.Tables("PUREM")
            ComboBox1.DataSource = yy
            ComboBox1.DisplayMember = "EmpName"

            Dim Ws As New SqlDataAdapter("SELECT * FROM PURFO ", strDbCon)
            Ws.Fill(a1, "PURFO")
            Dim xx As New DataTable
            xx = a1.Tables("PURFO")
            ComboBox2.DataSource = xx
            ComboBox2.DisplayMember = "OrderFormName"
    End Sub
     Public Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click
            myForm2a = New Form2a
            myForm2a.f2 = Me
            myForm2a.Show()
        End Sub
    以上為FORM2

    FORM3(FORM2a)的部份

    Public Class Form2a
        Friend f2 As Form2
        Dim strDbCon As String
        Dim c2 As DataSet

       Private Sub Form2a_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Dim Ys As New SqlDataAdapter("SELECT CusAcc FROM PURCU ", strDbCon)
            Ys.Fill(c2, "PURCU")
            Dim Yg As New DataTable
            Yg = c2.Tables("PURCU")
            DataGridView1.DataSource = Yg
            f2.SetText(DataGridView1.CurrentCell.Value)
        End Sub
    End Class

    很其怪的就是 Form2a內的DataGridView1就是沒資料  請問是我那裡有問題嗎?本想說這種方法測完之後然後再嘗試其大大大的方法,但是就是卡在此處即使在Form2a的Form2a的Form load加上
      strDbCon = "Persist Security Info=False;User ID=sa;pwd=sa;Initial Catalog=BUYER;Data Source=192.195.68.50"
            conn = New SqlConnection(strDbCon)
            conn.Open()
    還是沒值 所以很好奇我是那做錯 請各位大大告訴我一下  謝謝.
    ps:Run完後的錯誤訊息是Yg = c2.Tables("PURCU") is Null

    2009年11月23日 上午 02:39
  • 所以您Form2執行是沒問題的喔,請檢查資料庫BUYER,Table PURCU是否存在有值呢...
    2009年11月23日 上午 03:03
  • 親愛的大大你好:

                我PURCU是有值的,如果在Form2建一個DataGridView是可以顯示出資料,只是搬到Form2a這個Form就不行,所以想知道是那裡做錯?所以請各位大大指教一下。無限感激。

    2009年11月23日 上午 03:11
  •  Private Sub Form2a_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Dim Ys As New SqlDataAdapter("SELECT CusAcc FROM PURCU ", strDbCon)
            Ys.Fill(c2, "PURCU")
     
      這行沒有發生例外嗎?, 本想說若有發生例外的話可能是 c2 沒有 As New DataSet 的關係...
    Public Class Form2a
        Friend f2 As Form2
        Dim strDbCon As String
        Dim c2 As DataSet
    請試試看下列是否可行:

        Private Sub Form2a_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Dim Ys As New SqlDataAdapter("SELECT CusAcc FROM PURCU ", strDbCon)
    
            c2 = New DataSet
            Ys.Fill(c2, "PURCU")
    
            Dim Yg As DataTable = c2.Tables("PURCU")
            DataGridView1.DataSource = Yg
    
            f2.SetText(DataGridView1.CurrentCell.Value)
        End Sub
    • 已標示為解答 MichaelTsai10 2009年11月23日 上午 06:11
    2009年11月23日 上午 04:37
  • 感謝各位大大的指教,此部份終於OK.謝謝各位大大
    2009年11月23日 上午 06:11