none
跨執行緒作業無效 RRS feed

  • 問題

  • 我在使用多執行緒時
    遇到ComboBox  它就顯示跨執行緒作業無效
    我有上網找過  我大概知道什麼原因   但那些程式碼都沒說這動作做什麼用的
    而且都是textbox 請問一下我要怎麼去解決這問題



    這一個就不需要了
     Form.CheckForIllegalCrossThreadCalls = False  
    2009年9月25日 上午 07:55

解答

  • 奇怪了, 我剛用While跑了一次, 結果還是正常的
    程式碼如下: 畫面是一個具備兩個TabPage的TabControl, 兩個Button 和一個TextBox
    Public Class Form1
        Dim x As Boolean
        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 Running)
            myThread.IsBackground = True
            x = True
            myThread.Start()

        End Sub
        Delegate Sub TabControl1Delegate(ByVal TabControl1 As Object, ByVal Selectindex As Integer)

        Private Sub TabControl1Selectindex(ByVal TabControl1 As Object, ByVal Selectindex As Integer)
            If TabControl1.InVokeRequired Then
                Dim TCL1 As New TabControl1Delegate(AddressOf TabControl1Selectindex)
                TabControl1.invoke(TCL1, New Object() {TabControl1, Selectindex})

            Else
                Selectindex = TabControl1.SelectedIndex
                TextBox1.Text &= Selectindex & ","
            End If

        End Sub
        Sub Running()
            While x = True

                System.Threading.Thread.Sleep(50)
                Dim Selectedindex As Integer
                TabControl1Selectindex(TabControl1, Selectedindex)
            End While

        End Sub

        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            x = False
        End Sub
    End Class


    學而不思則罔, 思而不學則殆.
    如果你一直都看不懂、不想學習看懂、抗拒看懂MSDN Library的話,那你最好放棄想要寫好程式這件事
    • 已標示為解答 x32 2009年9月29日 上午 08:57
    2009年9月29日 上午 07:52
    版主

所有回覆

  • 跨執行緒作業無效: 存取控制項 'ComboBox1'


    這篇看過了嗎...
    • 已標示為解答 x32 2009年9月29日 上午 05:15
    • 已取消標示為解答 x32 2009年9月29日 上午 05:20
    2009年9月25日 上午 08:20
  • 自 VS2005 強化執行緒安全,變成必須透過委派,只要不是建立控制項的執行緒,就不能變更控制項內容,跟是哪個控制項無關,既有討論:
    http://social.msdn.microsoft.com/Search/zh-TW/?Refinement=112&query=thread%20%u59d4%u6d3e%20%u63a7%u5236%u9805


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年9月25日 上午 08:27
  • 下面的程式是我剛看委派寫法去寫多執行緒  最後還是一樣  跨執行緒作業無效:
    因為我還看不懂  要怎麼利用委派去解決
    有哪個大哥可以幫我一下  可以在後面註解說明一下 3q


        Delegate Sub TabControl1Delegate(ByVal TabControl1 As Object, ByRef Selectindex As Integer)
       
        Private Sub TabControl1Selectindex(ByVal TabControl1 As Object, ByRef Selectindex As Integer)
            Selectindex = TabControl1.SelectedIndex
        End Sub  
     
        Sub Running()
            Dim TCL1 As TabControl1Delegate = AddressOf TabControl1Selectindex
            Dim Selectedindex As Integer
            TCL1.Invoke(TabControl1, Selectedindex)
        End sub)
    2009年9月28日 上午 02:05
  • 不要傳控制項過去...
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年9月28日 上午 05:08
  • 不要傳控制項過去...
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    我是發現你要給控制項.text 這樣是沒問題的
    要是像我那樣TabControl1.SelectedIndex
    讀到的值就會變成0




    我本來自己依自己的想法也是沒有傳控制項
    我是看了joe hung 的那篇改的   還是一樣沒用

    Delegate Sub TabControl1Delegate(ByRef Selectindex As Integer)
       
        Private Sub TabControl1Selectindex(ByRef Selectindex As Integer)
            Selectindex = TabControl1.SelectedIndex
        End Sub  
     
        Sub Running()
            Dim TCL1 As TabControl1Delegate = AddressOf TabControl1Selectindex
            Dim Selectedindex As Integer
            TCL1.Invoke(Selectedindex)
        End sub)
    • 已編輯 x32 2009年9月28日 上午 09:12
    2009年9月28日 上午 06:00
  • 依這篇改呢?
    http://tlcheng.spaces.live.com/blog/cns!145419920BFD55A7!1440.entry


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年9月28日 上午 06:12
  • 我這寫倒是OK
    Public Class Form1

        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 Running)
            myThread.Start()

        End Sub
        Delegate Sub TabControl1Delegate(ByVal TabControl1 As Object, ByVal Selectindex As Integer)

        Private Sub TabControl1Selectindex(ByVal TabControl1 As Object, ByVal Selectindex As Integer)
            If TabControl1.InVokeRequired Then
                Dim TCL1 As New TabControl1Delegate(AddressOf TabControl1Selectindex)
                TabControl1.invoke(TCL1, New Object() {TabControl1, Selectindex})

            Else
                Selectindex = TabControl1.SelectedIndex
                MessageBox.Show(Selectindex)
            End If

        End Sub
        Sub Running()
            Dim Selectedindex As Integer
            TabControl1Selectindex(TabControl1, Selectedindex)
        End Sub
    End Class
    學而不思則罔, 思而不學則殆. 寫程式無他, 唯勤而已.
    • 已標示為解答 x32 2009年9月29日 上午 04:31
    • 已取消標示為解答 x32 2009年9月29日 上午 05:20
    2009年9月28日 下午 01:01
    版主
  • 我這寫倒是OK
    Public Class Form1

        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 Running)
            myThread.Start()

        End Sub
        Delegate Sub TabControl1Delegate(ByVal TabControl1 As Object, ByVal Selectindex As Integer)

        Private Sub TabControl1Selectindex(ByVal TabControl1 As Object, ByVal Selectindex As Integer)
            If TabControl1.InVokeRequired Then
                Dim TCL1 As New TabControl1Delegate(AddressOf TabControl1Selectindex)
                TabControl1.invoke(TCL1, New Object() {TabControl1, Selectindex})

            Else
                Selectindex = TabControl1.SelectedIndex
                MessageBox.Show(Selectindex)
            End If

        End Sub
        Sub Running()
            Dim Selectedindex As Integer
            TabControl1Selectindex(TabControl1, Selectedindex)
        End Sub
    End Class
    學而不思則罔, 思而不學則殆. 寫程式無他, 唯勤而已.
    我昨天就是這樣寫  結果也不能
    我剛把你寫的丟在一個新開的程式  結果可以
    丟在我的程式又不行
    我這樣講
    我那程式是被while包起來
    我用逐步執行  發現  這一段   Selectindex = TabControl1.SelectedIndex  
    selectindex有時讀到1  有時又變成0
    我發現到的差異就是你的按一次按鈕就只跑一次
    我的用while在跑    是這邊的問題嗎

        Sub Running()
            While 1
            {
            Application.DoEvents()
             System.Threading.Thread.Sleep(Run_Delay)
            Dim Selectedindex As Integer
            TabControl1Selectindex(TabControl1, Selectedindex)
            }
        End Sub
    2009年9月29日 上午 05:34
  • 你的TabControl應該是有兩個以上的Page. 如果是選擇第一個TabPage會得到0, 選擇第二個Tabpage會得到1..以此類推
    是否在程式執行中, 有去點選到TabControl , 以致於處在不同的TabPage下 ?
    還是你程式中有其它程序會去處理到TabPage變更之類的?

    學而不思則罔, 思而不學則殆.
    如果你一直都看不懂、不想學習看懂、抗拒看懂MSDN Library的話,那你最好放棄想要寫好程式這件事
    2009年9月29日 上午 06:55
    版主
  • 不是很懂你的意思  不是點選 TabControl 它會回你選擇第幾page
    我的程式是一個tabControl 分好幾個page 
    每個page裡都有一個datagridview
    這樣會影響到嗎

    我那個程式沒問題  因為一開始我用的是timer
    之後才把它改成 多執行緒  因為需要加入更多功能
    我在from_load那寫入Form.CheckForIllegalCrossThreadCalls = False
    這樣跑多執行緒 又沒問題了

    對了 現在又遇到一個問題
    我用多執行緒   在啟動myThread.Start()
    之後我想讓它暫停一下  不是sleep喔
    要怎麼弄   請告訴我一個順序
    因為我照著msdn  都寫說這個過時了
    停的下來   卻沒辦法在啟動   怎麼會這樣呢

    'Start()
    '讓執行緒開始執行

    'Sleep()
    '暫停執行緒一段指定的時間

    'Suppend()
    '當執行緒到達安全點時暫停

    'Abort()
    ' 當執行緒到達安全點時停止執行

    'Resume()
    '重新啟動暫停的執行緒

    'Join()
    '
    2009年9月29日 上午 07:37
  • 呃, 我的意思是在 Sub Running()
            While 1
            {
            Application.DoEvents()
             System.Threading.Thread.Sleep(Run_Delay)
            Dim Selectedindex As Integer
            TabControl1Selectindex(TabControl1, Selectedindex)
            }
        End Sub
    執行的過程中, 如果你有去點選TabPage, 它回傳的Index就會改變.

    至於暫停, 現在要用"等候控制代碼"
    你可以參考原有的討論
    [有關執行緒暫停、啟動的問題 ]
    [AutoResetEvent,ManualResetEvent ]
    學而不思則罔, 思而不學則殆.
    如果你一直都看不懂、不想學習看懂、抗拒看懂MSDN Library的話,那你最好放棄想要寫好程式這件事
    2009年9月29日 上午 07:43
    版主
  • 奇怪了, 我剛用While跑了一次, 結果還是正常的
    程式碼如下: 畫面是一個具備兩個TabPage的TabControl, 兩個Button 和一個TextBox
    Public Class Form1
        Dim x As Boolean
        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 Running)
            myThread.IsBackground = True
            x = True
            myThread.Start()

        End Sub
        Delegate Sub TabControl1Delegate(ByVal TabControl1 As Object, ByVal Selectindex As Integer)

        Private Sub TabControl1Selectindex(ByVal TabControl1 As Object, ByVal Selectindex As Integer)
            If TabControl1.InVokeRequired Then
                Dim TCL1 As New TabControl1Delegate(AddressOf TabControl1Selectindex)
                TabControl1.invoke(TCL1, New Object() {TabControl1, Selectindex})

            Else
                Selectindex = TabControl1.SelectedIndex
                TextBox1.Text &= Selectindex & ","
            End If

        End Sub
        Sub Running()
            While x = True

                System.Threading.Thread.Sleep(50)
                Dim Selectedindex As Integer
                TabControl1Selectindex(TabControl1, Selectedindex)
            End While

        End Sub

        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            x = False
        End Sub
    End Class


    學而不思則罔, 思而不學則殆.
    如果你一直都看不懂、不想學習看懂、抗拒看懂MSDN Library的話,那你最好放棄想要寫好程式這件事
    • 已標示為解答 x32 2009年9月29日 上午 08:57
    2009年9月29日 上午 07:52
    版主
  • 不是很懂你的意思  不是點選 TabControl 它會回你選擇第幾page
    我的程式是一個tabControl 分好幾個page 
    每個page裡都有一個datagridview
    這樣會影響到嗎

    我那個程式沒問題  因為一開始我用的是timer
    之後才把它改成 多執行緒  因為需要加入更多功能
    我在from_load那寫入Form.CheckForIllegalCrossThreadCalls = False
    這樣跑多執行緒 又沒問題了

    對了 現在又遇到一個問題
    我用多執行緒   在啟動myThread.Start()
    之後我想讓它暫停一下  不是sleep喔
    要怎麼弄   請告訴我一個順序
    因為我照著msdn  都寫說這個過時了
    停的下來   卻沒辦法在啟動   怎麼會這樣呢

    'Start()
    '讓執行緒開始執行

    'Sleep()
    '暫停執行緒一段指定的時間

    'Suppend()
    '當執行緒到達安全點時暫停

    'Abort()
    ' 當執行緒到達安全點時停止執行

    'Resume()
    '重新啟動暫停的執行緒

    'Join()
    '
    我終於知道發生什麼問題了
    在你的程式  在得到   Selectindex= TabControl1.SelectedIndex
    你立刻用msgbox 顯示出來
    而我是用 Delegate Sub TabControl1Delegate(ByVal TabControl1 As Object, ByRef Selectindex As Integer)
    我是用ref把值傳出來
    而這樣的話  我看它的程式會一直在tabcontrol1selectindex那跑來跑去   這就是我看到說  它一下子1  一下子又是0

    你在你第一個程式  改成Delegate Sub TabControl1Delegate(ByVal TabControl1 As Object, ByRef Selectindex As Integer)
    在把messagebox拿到running  就會看到跟我一樣的情形

    2009年9月29日 上午 08:30
  • 我改成以下這樣
      Dim x As Boolean
        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 Running)
            myThread.IsBackground = True
            x = True
            myThread.Start()

        End Sub
        Delegate Sub TabControl1Delegate(ByVal TabControl1 As Object, ByRef Selectindex As Integer)

        Private Sub TabControl1Selectindex(ByVal TabControl1 As Object, ByRef Selectindex As Integer)
            If TabControl1.InVokeRequired Then
                Dim TCL1 As New TabControl1Delegate(AddressOf TabControl1Selectindex)
                TabControl1.invoke(TCL1, New Object() {TabControl1, Selectindex})

            Else
                Selectindex = TabControl1.SelectedIndex
                '  TextBox1.Text &= Selectindex & ","
            End If

        End Sub
        Sub Running()
            While x = True

                System.Threading.Thread.Sleep(50)
                Dim Selectedindex As Integer
                TabControl1Selectindex(TabControl1, Selectedindex)
            End While

        End Sub
    用中斷點看, selectindex一直都是0啊?

    學而不思則罔, 思而不學則殆.
    如果你一直都看不懂、不想學習看懂、抗拒看懂MSDN Library的話,那你最好放棄想要寫好程式這件事
    2009年9月29日 上午 08:38
    版主
  • 對呀   它值根本傳不出來   才會我看到的都是0
    我看這是微軟自己出的大包



    我最後在外面宣告一個 全域陣列 丟進去
    讀出來的值就正確了
    2009年9月29日 上午 08:44
  • 這個問題的正解應該是, 我們認為用ByRef 從執行緒將 Selectedindex變數傳到委派函式之後, 如果值在委派函式中改變就應該在Sub Running()的Selectedindex變數值也會改變.
    你的疑問應該是為什麼會沒有改變.
    原因出在我們的函式中有這麼一段
    TabControl1.invoke(TCL1, New Object() {TabControl1, Selectindex})
    也就是當必須Invoke之時, 參數是以一個新的Object 陣列執行個體傳進去的
    這個陣列的元素0是TabControl1 , 而元素1 是Selectindex. 毛病就出在這邊
    事實上這個陣列的元素1 和ByRef傳進來的Selectindex並不具備相同的參考指標 , 因為我們是把ByRef Selectindex As Integer 這個變數的 指派給陣列的元素1
    也就是說, 當我們Invoke之後執行的 Selectindex = TabControl1.SelectedIndex 這個Selectindex變數和 ByRef Selectindex As Integer 這兩個是不一樣的.
    所以ByRef Selectindex As Integer這個的參考指標記憶體的內容值一直都沒有改變
    就.Net的變數傳遞原理來說, 如果硬要把實值型別這樣傳遞, 有一種方法是自訂類別去做 (因為非實值型別的東西, 陣列指派的就是參考指標而不是值)
    類似像以下這樣
     Dim x As Boolean
        Public Class myCS
            Public Selectedindex As Object
        End Class

        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 Running)
            myThread.IsBackground = True
            x = True
            myThread.Start()

        End Sub
        Delegate Sub TabControl1Delegate(ByRef TabControl1 As Object, ByRef myx As myCS)

        Private Sub TabControl1Selectindex(ByRef TabControl1 As Object, ByRef myx As myCS)
            '   Dim myObj() As Object = New Object() {TabControl1, Selectindex}
            If TabControl1.InVokeRequired Then
                Dim TCL1 As New TabControl1Delegate(AddressOf TabControl1Selectindex)
                TabControl1.invoke(TCL1, New Object() {TabControl1, myx})
                ' TabControl1.invoke(TCL1, myObj)
            Else
                myx.Selectedindex = TabControl1.SelectedIndex
            End If
        End Sub
        Sub Running()
            Dim myx As New myCS
            myx.Selectedindex = 0
            While x = True
                System.Threading.Thread.Sleep(50)
                TabControl1Selectindex(TabControl1, myx)
            End While

        End Sub

        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            x = False
        End Sub
    我利用一個自訂的myCS類別來包住Selectedindex變數. 這樣就不會有跳來跳去的問題

    學而不思則罔, 思而不學則殆.
    如果你一直都看不懂、不想學習看懂、抗拒看懂MSDN Library的話,那你最好放棄想要寫好程式這件事
    • 已提議為解答 有夢最美 2016年3月11日 下午 01:02
    2009年9月29日 上午 10:28
    版主