簡體   English   中英

如何獲取winform的GUI線程?

[英]How do I get the GUI thread of winform?

我有一個帶有多個 GUI 線程的 winforms 應用程序。 我希望它們能夠訪問彼此的線程對象,而不必單獨跟蹤該信息。

.NET 中是否有 function 我可以提供 winforms 控件或 window object,然后取回線程? 或者 API 中的 function 我可以調用 threadID?

(請不要評論說我應該用另一種方式來做......這也不是關於跨線程 window 操作。)

謝謝!

編輯

對於那些出於某種原因相信我的斜體文字的人,恭喜你,你被錄用了!! 這是問題所在:

“應用程序通過完全鎖定在野外崩潰,也就是說,它停止響應。非常間歇性,並試圖調試它,它似乎永遠不會發生。”

那怎么辦? 在程序中安裝一個用戶可以在我們的指導下激活的選項,從而從同一應用程序中的另一個 GUI 線程,在主 GUI 線程上執行 thread.abort,然后我們可以在錯誤日志中查看調用堆棧。 Viola,在不到一天的時間內發現了一個無法調試的錯誤。 (現在停止,它與濫用多線程無關:-)

我承認我幾乎沒有問過這個問題,我這樣做的原因是我可以看到對主窗體的 object 引用,但它的線程沒有任何引用。 我給 Chris Shain 的答案是 a/c 這是一種快速的方法,不幸的是當線程掛起時,我將無法進行調用(它也會掛起)。 進一步挖掘揭示了 GetWindowThreadProcessId API 調用。 但它是一個非托管線程 ID,顯然將其轉換為托管線程 ID 很復雜。

所以我硬着頭皮加入了對主 UI 線程的全局引用。 本來會張貼它開始,但還沒有寫。

現在,如果您原諒 VB...

在主要公共模塊/靜態 class 中:

Public GUIThread As Threading.Thread
Sub Main()
    '' //  Create app main window
    ShellForm = New frmShell
    '' // Save main GUI Thread for abort routine
    GUIThread = Threading.Thread.CurrentThread  
    If GetSetting("MyApp", "Testing", "CrashDebug", "False") = "True" Then
            '' //  DO NOT run the pgm. like this normally - with try/catch around
            '' //  Application.Run - or uncaught errors will kill the whole app!!!
        Try

            '' // This is the other of the ‘Multiple GUI threads’ I talked
            '' // about in the Orig Post.
            Dim t As New Threading.Thread(AddressOf StartCrashDebug)
            t.Start()

            Application.Run(ShellForm)
        Catch ex As Exception
            '' // This error routine passes errors off to another thread which 
            '' // logs them (and also shows messages)
            MyLogError(ex, "CrashDebug - Main Window blew up")
        End Try
    Else
        '' // Normal mode - uncaught errors will get caught by UnhandledException, 
        '' // logged, and Winforms will keep the GUI alive (since we _do_ care 
        '' // more about users than computers right ;-)
        Application.Run(ShellForm)
    End If
End Sub
Sub StartCrashDebug()
    Dim f As New frmCrashFinder
    '' // Starting a window like this on a separate thread makes it ‘Another 
    '' // GUI thread’ for winforms, by design
    Application.Run(f)
 End Sub

在“中止者”WinForm 中:

Public Class frmCrashFinder 
    Inherits Windows.Form

    Private Sub Abort_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Abort.Click
        GUIThread.Abort()
    End Sub
End Class

Windows 窗體中的所有 GUI 元素通常在單個線程上完成。 我強烈建議避免以任何其他方式嘗試這樣做。

通過將 Control.Invoke 或 Control.BeginInvoke 與任何 Control 結合使用,您始終可以將代碼封送到該線程。

如果你真的想獲得線程的 ID(不確定這有什么用......?),你可以使用:

int GetControlThreadId(Control control)
{
    int threadId;
    control.Invoke( new Action( () => 
       {
           threadId = Thread.CurrentThread.ManagedThreadId;
       }));
    return threadId;
}

如果您的代碼不在窗體或控件中,則可以使用

if (System.Windows.Forms.Form.ActiveForm.InvokeRequired)
{
    System.Windows.Forms.Form.ActiveForm.Invoke(...);
}

應該這樣做,但是我同意其他海報的觀點,即出於其他原因,這可能是錯誤的做法......

var thatWindowsThread = (Thread)(WhateverWindow.Invoke(()=>Thread.CurrentThread);

WindowsFormsSynchronizationContext.Current具有PostSend方法,您可以從中將命令委托給 UI 線程

如果您無權訪問任何可以從中提取線程或SynchronizationContext窗體或窗口或控件,則可以使用

        System.Windows.Forms.Application.OpenForms    

這對我有用。 System.Windows.Forms.Form.ActiveForm在我的情況下為 null,但 Metro 的回答讓我更仔細地研究System.Windows.Forms中的靜態類。 使用

System.Windows.Forms.Application.OpenForms.Invoke(...) or BeginInvoke. 

您可以從其他答案中獲得其余部分。

更好的答案:

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsGUIThread([MarshalAs(UnmanagedType.Bool)] bool bConvert);

http://pinvoke.net/default.aspx/Constants.IsGUIThread

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM