【问题标题】:How do I get the GUI thread of winform?winform的GUI线程如何获取?
【发布时间】:2011-02-01 19:12:12
【问题描述】:

我有一个带有多个 GUI 线程的 winforms 应用程序。我希望他们能够访问彼此的线程对象,而不必单独跟踪该信息。

.NET 中是否有一个函数可以提供一个 winforms 控件或窗口对象,然后取回线程?或者API中的一个函数我可以为threadID调用?

(请不要让 cmets 说我应该以另一种方式来做......这也与跨线程窗口操作无关。)

谢谢!

编辑

对于那些出于某种原因相信我的斜体文字的人,恭喜你,你被录用了!问题是:

“应用程序因完全锁定而在野外崩溃,即停止响应。非常断断续续,尝试调试它似乎永远不会发生。”

那该怎么办?在程序中安装一个选项,用户可以在我们的指导下激活,从而从同一个应用程序中的另一个 GUI 线程,在主 GUI 线程上执行 thread.abort,然后我们可以查看错误日志中的调用堆栈。 Viola,不到一天就发现了一个无法调试的错误。 (停止,这与滥用多线程无关:-)

我承认我几乎没有问这个,我这样做的原因是我可以看到对主窗体的对象引用,但它的线程没有任何引用。我正在给 Chris Shain 答案 a/c,这是一种快速的方法,不幸的是,当线程挂起时,我将无法进行调用(它也会挂起)。多一点挖掘揭示了 GetWindowThreadProcessId API 调用。但它是一个非托管线程 ID,显然将其转换为托管线程 ID 会很复杂。

所以我硬着头皮对主 UI 线程进行了全局引用。本来想一开始就发的,但是还没写。

现在请原谅 VB...

在主要公共模块/静态类中:

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

【问题讨论】:

  • 请不要让 cmets 说我应该用另一种方法来做 对,因为你的方法是解决问题的唯一可能方法。不要假设没有人能想出比你已经拥有的更好的主意。
  • 这没有意义,线程不“拥有”一个对象。
  • 请注意,您的问题标题与您在问题正文中实际询问的内容不一致。
  • @Ed S.(作为记录,他在我添加编辑之前说过这个)...如果我能找到一个更好的解决方案来解决这个特殊问题,我会很高兴!当然,我也不认为这真的会奏效!
  • @stakx,@Hans Passant,为糟糕的描述道歉;我的英语成绩很差。 从 Main() 线程执行 application.run(winform1);启动执行 application.run(winform2) 的 thread2。 mainthread 是第一个 GUI 线程,“属于”(或反之亦然)winform1 和该线程创建的任何其他窗口; thread2 和 winform2 也是如此。

标签: c# .net vb.net winapi


【解决方案1】:

Windows 窗体中的所有 GUI 元素通常在单个线程上完成。我强烈建议避免尝试以任何其他方式执行此操作。

您始终可以通过将 Control.Invoke 或 Control.BeginInvoke 与任何 Control 一起使用来将代码编组到该线程。

如果你真的想获取线程的 ID(不确定这有什么用..?),你可以使用:

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

【讨论】:

  • 一旦有了Thread 对象或ThreadId,就没有合理的方法可以从线程中检索“数据”。从单独的线程中检索数据可能表明需要为每个提供 GUI 的线程提供数据对象。
  • @sixlettervariables:是的 - 在我看来,这绝对是无用的代码......只是展示了 如何 它会完成,但仍然没有理由......
  • @FastAI:编辑确实解释了您为什么需要线程 ID。但是,您在编辑之前的问题包括“[访问]彼此的线程对象”,这使我们无法确定“正确答案”。
【解决方案2】:

如果您的代码不在表单或控件中,您可以使用

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

【讨论】:

  • 当我的窗口最小化时,它会得到一个NullReferenceException(正如预期的那样,因为它不再是活动窗口了)。如何获取 GUIThread 并根据我的意愿调用它?
  • 如果是因为你想更新窗口上的东西,你必须有对窗口的引用。然后你可以只使用窗口引用而不是“System.Windows.Forms.Form.ActiveForm”。但是,如果是这种情况,我会在表单上创建一个 Method 来执行所需的操作,然后在 Method 中处理线程问题。见stackoverflow.com/a/25903258/18978
  • 非常感谢!我会这样尝试。
【解决方案3】:

应该这样做,但是我同意其他发帖人的观点,由于其他原因,这可能是错误的做法......

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

【讨论】:

    【解决方案4】:

    WindowsFormsSynchronizationContext.Current 具有 PostSend 方法,您可以从中将命令委托给 UI 线程

    【讨论】:

      【解决方案5】:

      如果您无权访问任何表单或窗口或控件,您可以从中提取线程或SynchronizationContext,您可以使用

              System.Windows.Forms.Application.OpenForms    
      

      这对我有用。 System.Windows.Forms.Form.ActiveForm 在我的情况下为空,但 M​​etro 的回答让我更仔细地研究了 System.Windows.Forms 中的静态类。 使用

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

      你可以从其他答案中得到其余的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-11-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多