none
DataTable 與 DataGridView RRS feed

  • 問題

  • 我將一個DataTable 指定給 一個DataGridview

    我有個觀念的問題想請問大家

    我 會在 thread 中去 更改 datatable 中的值  更改的值會反應在UI 端的 DataGridView上

    這樣不是 應該會有跨 執行緒 的問題嘛?!

    例如:

    m_foundrow["urserName"]="hhh";

    這一段若擺在thread中  對應的 Datagridview 呈現的值也會變

    跟我想像的會出現 跨執行緒的問題 有落差

    請大家幫我離清觀念

    2010年4月1日 下午 12:17

解答

  • 基本上如果使用執行緒的話, 透過委派處理是比較正確的做法. 你現在的做法跑起來好像正確, 但是可能會隱藏著未知的問題.

    我剛剛寫了一個程式測試, 發現不使用委派的狀況下, 它在編輯器的偵錯模式啟動與直接執行exe檔會有不同的行為. 這意味著這樣的處理方式會有風險.

    習慣上我會使用多執行緒處理數據, 然後再呼叫委派來將結果值傳給DataTable (當此DataTable和 UI 控制項有繫結時), 而不會直接在執行緒中更動DataTable.

    以下為範例, 其中 X Method 為使用委派的方式, Y Method 為不使用委派的方式.

    Public Class Form1
        Dim DT As New DataTable
        Delegate Sub SetMsgDTCallBack(ByVal myStr As String)
        Public Sub DisplayMsgDGV(ByVal myStr As String)
            If Me.DataGridView1.InvokeRequired = True Then
                Dim d As New SetMsgDTCallBack(AddressOf DisplayMsgDGV)
                Me.DataGridView1.Invoke(d, New Object() {myStr})
            Else
                Try
                    Dim myRow As DataRow = DT.NewRow
                    myRow(0) = myStr
                    DT.Rows.Add(myRow)
                Catch ex As Exception
                    MessageBox.Show(ex.ToString)
                End Try
            End If
        End Sub
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            DT.Columns.Add("COL")
            DataGridView1.DataSource = DT

        End Sub

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim myThread As New System.Threading.Thread(AddressOf X)
            myThread.Start()
        End Sub
        Private Sub X(ByVal obj As Object)
            Dim myStr As String = "ABC"
            DisplayMsgDGV(myStr)

        End Sub

        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            Dim myThread As New System.Threading.Thread(AddressOf Y)
            myThread.Start()
            '   Me.Refresh()
        End Sub
        Private Sub Y(ByVal obj As Object)
            Dim myRow As DataRow = DT.NewRow()
            myRow(0) = "XYZ"
            DT.Rows.Add(myRow)
        End Sub
    End Class


    MSDN 文件庫很重要
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    進步的人會找尋自己程式中的缺點,半桶水則把自己程式的錯誤推到不相干事物的身上
    • 已標示為解答 布利 2010年4月5日 下午 01:30
    2010年4月3日 上午 05:36
    版主
  • 類似這樣

    Public Class Form1
        Dim DT As New DataTable
        Delegate Sub SetMsgDTCallBack(ByVal myRowData As RowData)
        Public Sub DisplayMsgDGV(ByVal myRowData As RowData)
            If Me.DataGridView1.InvokeRequired = True Then
                Dim d As New SetMsgDTCallBack(AddressOf DisplayMsgDGV)
                Me.DataGridView1.Invoke(d, New Object() {myRowData})
            Else
                Try
                    Dim myRow As DataRow = DT.NewRow
                    myRow(0) = myRowData.Col1
                    myRow(1) = myRowData.Col2
                    DT.Rows.Add(myRow)
                Catch ex As Exception
                    MessageBox.Show(ex.ToString)
                End Try
            End If
        End Sub

        Public Structure RowData
            Public Col1 As Integer
            Public Col2 As String
        End Structure



        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            DT.Columns.Add("COL1")
            DT.Columns.Add("COL2")
            DataGridView1.DataSource = DT

        End Sub

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim myThread As New System.Threading.Thread(AddressOf X)
            myThread.Start()
        End Sub
        Private Sub X(ByVal obj As Object)
            Dim myRowData As RowData
            myRowData.Col1 = 0
            myRowData.Col2 = "Test"
            DisplayMsgDGV(myRowData)
        End Sub

    End Class


    MSDN 文件庫很重要
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    進步的人會找尋自己程式中的缺點,半桶水則把自己程式的錯誤推到不相干事物的身上
    • 已標示為解答 布利 2010年4月5日 下午 01:29
    2010年4月5日 下午 01:19
    版主

所有回覆

  • 基本上如果使用執行緒的話, 透過委派處理是比較正確的做法. 你現在的做法跑起來好像正確, 但是可能會隱藏著未知的問題.

    我剛剛寫了一個程式測試, 發現不使用委派的狀況下, 它在編輯器的偵錯模式啟動與直接執行exe檔會有不同的行為. 這意味著這樣的處理方式會有風險.

    習慣上我會使用多執行緒處理數據, 然後再呼叫委派來將結果值傳給DataTable (當此DataTable和 UI 控制項有繫結時), 而不會直接在執行緒中更動DataTable.

    以下為範例, 其中 X Method 為使用委派的方式, Y Method 為不使用委派的方式.

    Public Class Form1
        Dim DT As New DataTable
        Delegate Sub SetMsgDTCallBack(ByVal myStr As String)
        Public Sub DisplayMsgDGV(ByVal myStr As String)
            If Me.DataGridView1.InvokeRequired = True Then
                Dim d As New SetMsgDTCallBack(AddressOf DisplayMsgDGV)
                Me.DataGridView1.Invoke(d, New Object() {myStr})
            Else
                Try
                    Dim myRow As DataRow = DT.NewRow
                    myRow(0) = myStr
                    DT.Rows.Add(myRow)
                Catch ex As Exception
                    MessageBox.Show(ex.ToString)
                End Try
            End If
        End Sub
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            DT.Columns.Add("COL")
            DataGridView1.DataSource = DT

        End Sub

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim myThread As New System.Threading.Thread(AddressOf X)
            myThread.Start()
        End Sub
        Private Sub X(ByVal obj As Object)
            Dim myStr As String = "ABC"
            DisplayMsgDGV(myStr)

        End Sub

        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            Dim myThread As New System.Threading.Thread(AddressOf Y)
            myThread.Start()
            '   Me.Refresh()
        End Sub
        Private Sub Y(ByVal obj As Object)
            Dim myRow As DataRow = DT.NewRow()
            myRow(0) = "XYZ"
            DT.Rows.Add(myRow)
        End Sub
    End Class


    MSDN 文件庫很重要
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    進步的人會找尋自己程式中的缺點,半桶水則把自己程式的錯誤推到不相干事物的身上
    • 已標示為解答 布利 2010年4月5日 下午 01:30
    2010年4月3日 上午 05:36
    版主
  • 基本上如果使用執行緒的話, 透過委派處理是比較正確的做法. 你現在的做法跑起來好像正確, 但是可能會隱藏著未知的問題.

    我剛剛寫了一個程式測試, 發現不使用委派的狀況下, 它在編輯器的偵錯模式啟動與直接執行exe檔會有不同的行為. 這意味著這樣的處理方式會有風險.

    習慣上我會使用多執行緒處理數據, 然後再呼叫委派來將結果值傳給DataTable (當此DataTable和 UI 控制項有繫結時), 而不會直接在執行緒中更動DataTable.

    以下為範例, 其中 X Method 為使用委派的方式, Y Method 為不使用委派的方式.

    Public Class Form1
        Dim DT As New DataTable
        Delegate Sub SetMsgDTCallBack(ByVal myStr As String)
        Public Sub DisplayMsgDGV(ByVal myStr As String)
            If Me.DataGridView1.InvokeRequired = True Then
                Dim d As New SetMsgDTCallBack(AddressOf DisplayMsgDGV)
                Me.DataGridView1.Invoke(d, New Object() {myStr})
            Else
                Try
                    Dim myRow As DataRow = DT.NewRow
                    myRow(0) = myStr
                    DT.Rows.Add(myRow)
                Catch ex As Exception
                    MessageBox.Show(ex.ToString)
                End Try
            End If
        End Sub
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            DT.Columns.Add("COL")
            DataGridView1.DataSource = DT

        End Sub

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim myThread As New System.Threading.Thread(AddressOf X)
            myThread.Start()
        End Sub
        Private Sub X(ByVal obj As Object)
            Dim myStr As String = "ABC"
            DisplayMsgDGV(myStr)

        End Sub

        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            Dim myThread As New System.Threading.Thread(AddressOf Y)
            myThread.Start()
            '   Me.Refresh()
        End Sub
        Private Sub Y(ByVal obj As Object)
            Dim myRow As DataRow = DT.NewRow()
            myRow(0) = "XYZ"
            DT.Rows.Add(myRow)
        End Sub
    End Class


    MSDN 文件庫很重要
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    進步的人會找尋自己程式中的缺點,半桶水則把自己程式的錯誤推到不相干事物的身上


    其實 我有發現一個現像  但可能只是湊巧

    就是  若是在 DataTable 中加一筆資料 沒有用 invoke 的話  DataGridview 的怪怪的

    但若是 只改 Datatable中的值 例如 row["xxx"]=xx;  好像就不會有問題

    但又不知怎麼去解釋  請好心人  幫我解惑了~~~

    2010年4月3日 下午 05:31
  • 基本上如果使用執行緒的話, 透過委派處理是比較正確的做法. 你現在的做法跑起來好像正確, 但是可能會隱藏著未知的問題.

    我剛剛寫了一個程式測試, 發現不使用委派的狀況下, 它在編輯器的偵錯模式啟動與直接執行exe檔會有不同的行為. 這意味著這樣的處理方式會有風險.

    習慣上我會使用多執行緒處理數據, 然後再呼叫委派來將結果值傳給DataTable (當此DataTable和 UI 控制項有繫結時), 而不會直接在執行緒中更動DataTable.

    以下為範例, 其中 X Method 為使用委派的方式, Y Method 為不使用委派的方式.

    Public Class Form1
        Dim DT As New DataTable
        Delegate Sub SetMsgDTCallBack(ByVal myStr As String)
        Public Sub DisplayMsgDGV(ByVal myStr As String)
            If Me.DataGridView1.InvokeRequired = True Then
                Dim d As New SetMsgDTCallBack(AddressOf DisplayMsgDGV)
                Me.DataGridView1.Invoke(d, New Object() {myStr})
            Else
                Try
                    Dim myRow As DataRow = DT.NewRow
                    myRow(0) = myStr
                    DT.Rows.Add(myRow)
                Catch ex As Exception
                    MessageBox.Show(ex.ToString)
                End Try
            End If
        End Sub
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            DT.Columns.Add("COL")
            DataGridView1.DataSource = DT

        End Sub

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim myThread As New System.Threading.Thread(AddressOf X)
            myThread.Start()
        End Sub
        Private Sub X(ByVal obj As Object)
            Dim myStr As String = "ABC"
            DisplayMsgDGV(myStr)

        End Sub

        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            Dim myThread As New System.Threading.Thread(AddressOf Y)
            myThread.Start()
            '   Me.Refresh()
        End Sub
        Private Sub Y(ByVal obj As Object)
            Dim myRow As DataRow = DT.NewRow()
            myRow(0) = "XYZ"
            DT.Rows.Add(myRow)
        End Sub
    End Class


    MSDN 文件庫很重要
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    進步的人會找尋自己程式中的缺點,半桶水則把自己程式的錯誤推到不相干事物的身上


    其實 我有發現一個現像  但可能只是湊巧

    就是  若是在 DataTable 中加一筆資料 沒有用 invoke 的話  DataGridview 的怪怪的

    但若是 只改 Datatable中的值 例如 row["xxx"]=xx;  好像就不會有問題

    但又不知怎麼去解釋  請好心人  幫我解惑了~~~


    請高手們幫幫忙 

    我用google大師  查了 一下

    也找不出個所以然

    到底  怎樣的觀念才對呢?!

    2010年4月5日 下午 12:49
  • 我不是說了嗎 ? 使用委派才是正確的作法.

    MSDN 文件庫很重要
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    進步的人會找尋自己程式中的缺點,半桶水則把自己程式的錯誤推到不相干事物的身上
    2010年4月5日 下午 12:52
    版主
  • 我不是說了嗎 ? 使用委派才是正確的作法.

    MSDN 文件庫很重要
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    進步的人會找尋自己程式中的缺點,半桶水則把自己程式的錯誤推到不相干事物的身上


    不好意思 

    那想請問一下  若我要更新的是  DataTable 中的其中一個 row 值

    row["xxx"]=xx; 

    這樣要如何去寫   委派 

    因為  row["xxx"]  可能是 不同型別 

    傷腦筋  因為  若有十幾個 column 要更新

    例如:

    row=DT.select("Name='hi'");

    row["xxx"]="string; 

    row["xxx"]=0.01; 

    row["xxx"]=true; 

    row["xxx"]=xx; 

    row["xxx"]=xx; 

    .....

    這樣就滿麻煩的耶  請幫忙一下 

     

     

    2010年4月5日 下午 01:01
  • 你可以先寫一個類別或結構來包整個Row的值啊 . 然後把這個類別的執行個體 (or 結構) 傳進委派函式不得了.
    MSDN 文件庫很重要
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    進步的人會找尋自己程式中的缺點,半桶水則把自己程式的錯誤推到不相干事物的身上
    2010年4月5日 下午 01:06
    版主
  • 你可以先寫一個類別或結構來包整個Row的值啊 . 然後把這個類別的執行個體 (or 結構) 傳進委派函式不得了.
    MSDN 文件庫很重要
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    進步的人會找尋自己程式中的缺點,半桶水則把自己程式的錯誤推到不相干事物的身上


    Bill 大大  不好意思  不太瞭解耶

    小弟愚昧  想請您  明示   謝謝~~

    2010年4月5日 下午 01:09
  • 類似這樣

    Public Class Form1
        Dim DT As New DataTable
        Delegate Sub SetMsgDTCallBack(ByVal myRowData As RowData)
        Public Sub DisplayMsgDGV(ByVal myRowData As RowData)
            If Me.DataGridView1.InvokeRequired = True Then
                Dim d As New SetMsgDTCallBack(AddressOf DisplayMsgDGV)
                Me.DataGridView1.Invoke(d, New Object() {myRowData})
            Else
                Try
                    Dim myRow As DataRow = DT.NewRow
                    myRow(0) = myRowData.Col1
                    myRow(1) = myRowData.Col2
                    DT.Rows.Add(myRow)
                Catch ex As Exception
                    MessageBox.Show(ex.ToString)
                End Try
            End If
        End Sub

        Public Structure RowData
            Public Col1 As Integer
            Public Col2 As String
        End Structure



        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            DT.Columns.Add("COL1")
            DT.Columns.Add("COL2")
            DataGridView1.DataSource = DT

        End Sub

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim myThread As New System.Threading.Thread(AddressOf X)
            myThread.Start()
        End Sub
        Private Sub X(ByVal obj As Object)
            Dim myRowData As RowData
            myRowData.Col1 = 0
            myRowData.Col2 = "Test"
            DisplayMsgDGV(myRowData)
        End Sub

    End Class


    MSDN 文件庫很重要
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    進步的人會找尋自己程式中的缺點,半桶水則把自己程式的錯誤推到不相干事物的身上
    • 已標示為解答 布利 2010年4月5日 下午 01:29
    2010年4月5日 下午 01:19
    版主