2014-09-03 63 views
2

這是我的情況,有2個班,我的主窗體Form1:VB.NET調用可以到窗口句柄已創建不能在一個控件調用,但手柄創建

Class1的:有一個方法doSomethingAndCall(回調),它創建了一個新的線程 類2:具有動態創建的控件有一個按鈕,觸發Class1.doSomethingAndCall(newCallback)

代碼它看起來像這樣(它開始於Class2.Button_Click):

Class Class1 
    public shared sub doSomethingAndCallAsync(state as object) 
    Console.WriteLine(Form1.InvokeRequired) 'output: false 
    Console.WriteLine(Form1.IsHandleCreated) 'output: false 
    Form1.Invoke(state.callback) 'throws System.InvalidOperationException 
    end sub 

    public shared sub doSomethingAndCall(callback as object) 
    System.Threading.ThreadPool.QueueUserWorkItem(AddressOf doSomethingAndCallAsync, New With {.callback = callback}) 
    end sub 
End Class 

Class Class2 
    Public Delegate Sub doSomethingDelegate() 

    Public Sub doSomething() 
    Console.WriteLine("success!") 
    End Sub 

    Public Sub Button_Click(ByVal sender As Object, ByVal e As System.EventArgs) 
    Class1.doSomethingAndCall(New doSomethingDelegate(AddressOf doSomething)) 
    End Sub 
End Class 

ex行爲例外,我得到的是:

調用或BeginInvoke可直到窗口句柄已創建

不能在控制打來電話,我可以看到Console.WriteLine命令行中4顯示我,形式是真的沒有創建。所以我說這個處理程序,現在它得到的真正困惑:

Private Sub Form1_HandleCreated(sender As Object, e As System.EventArgs) Handles Me.HandleCreated 
     Console.WriteLine("Handle created") 'Output: Handle created, when running program 
    End Sub 

    Private Sub Form1_HandleDestroyed(sender As Object, e As System.EventArgs) Handles Me.HandleDestroyed 
     Console.WriteLine("Handle destroyed") 'Will never Output! 
    End Sub 

所以它的創建和銷燬從來沒有,但如果我按一下按鈕它仍然不是avaible? - 任何人都可以解釋我發生了什麼以及如何調用回調正確,謝謝!

+0

什麼是state.callback,它是做什麼的? – Derek 2014-09-03 13:00:33

+0

你確定你正在使用Form1的實例嗎?它看起來像是在說一個類型的'Form1.Invoke',而不是那種類型的實例。 – JoelC 2014-09-03 13:11:48

+0

@Derek:當使用線程池時,只能向線程傳遞1個參數(作爲對象),這是狀態。但是,如果您必須傳遞多於1個參數,則可以執行如下操作:New With {.callback = callback}。所以可以傳遞大量的參數。在我的例子中,回調函數是new doSomethingDelegate(AddressOf doSomething),我想在doSomethingAndCallAsync中調用它。如果你或其他人知道更好的方式,請告訴我:) – MaBi 2014-09-03 13:27:12

回答

4

My.Forms.Form1 aka的實例。 Form1將在每個線程中有所不同。您需要處理正確的實例。拖放一個按鈕到您的Form1,並添加以下代碼:

Public Class Form1 

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
     Threading.Tasks.Task.Factory.StartNew(Sub() Class1.Wrong()) 
     Threading.Tasks.Task.Factory.StartNew(Sub() Class1.Correct(Me)) 
    End Sub 

End Class 

Public Class Class1 

    Public Shared Sub Wrong() 
     Debug.WriteLine(String.Format("(Other thread, wrong) InvokeRequired={0}, IsHandleCreated={1}", Form1.InvokeRequired, Form1.IsHandleCreated)) 
    End Sub 

    Public Shared Sub Correct(instance As Form1) 
     Debug.WriteLine(String.Format("(Other thread, correct) InvokeRequired={0}, IsHandleCreated={1}", instance.InvokeRequired, instance.IsHandleCreated)) 
    End Sub 

End Class 

輸出

(其它線程,正確的)InvokeRequired =真,IsHandleCreated =真

(其他線程,錯誤)InvokeRequired = False,IsHandleCreated = False

+0

謝謝解決方案「傳遞form1作爲參數」工作我。是否有一個原因,你使用Threading.Tasks.Task.Factory.StartNew(MSDN:創建並啓動一個任務。)而不是ThreadPool.QueueUserWorkItem(MSDN:隊列一個方法執行)目前我在想(並測試它們)他們做的是相同的,還是? – MaBi 2014-09-03 18:39:07

+0

@MaBi爲什麼我使用'Task'只是因爲它是一個更新,更強大的工具。你可能想閱讀這個SO帖子:[ThreadPool.QueueUserWorkItem vs Task.Factory.StartNew](http://stackoverflow.com/questions/9200573/threadpool-queueuserworkitem-vs-task-factory-startnew)。注意Jon的(接受的答案)結論,他重申了CLR團隊的ThreadPool開發人員已經說過的內容:*「任務現在是將工作排入線程池的首選方式。」* – 2014-09-04 05:49:10

+1

幫助我,非常感謝! – MaBi 2014-09-04 09:45:21

相關問題