【问题标题】:C# - Possible to safely have an owned form in a separate thread?C# - 可以在单独的线程中安全地拥有一个拥有的表单吗?
【发布时间】:2010-09-26 03:13:59
【问题描述】:

我正在尝试为我用 C# 编写的应用程序编写专门的屏幕键盘 (OSK)。为此,我创建了一个表单,上面有几个代表键的按钮,单击它们会调用SendKeys 并发送相应的键。

此表单归应用程序首次启动时显示的主窗口所有,使用Owner 属性。这样,每当用户聚焦应用程序时,OSK 就会弹出,如果主窗口被拖动到它上面,它就会停留在主窗口的顶部。

这一切都很好,但是因为我有模式对话框,我也想与 OSK 一起使用,我试图在一个单独的线程中创建它,完成它自己的消息循环(通过Application.Run)所以它仍然可以可用于主线程中的任何模式对话框。

问题在于,显然,由于跨线程调用,处于单独的线程中可能会导致InvalidOperationExceptions。这方面的一个具体示例是,当从新线程调用 Application.Run(osk) 时,会发生跨线程错误,因为它试图用所有者(主窗口)更新窗口句柄。

我的问题是,是否可以在与所有者分开的线程上以安全的方式拥有自有表单?而且,如果做不到这一点,是否可以模拟拥有的表单的特性(即仅在主窗口始终位于顶部,并在主窗口获得焦点时弹出)?

谢谢,如有混淆,请见谅。

【问题讨论】:

  • 为什么要在单独的 UI 线程中使用模态对话框?似乎如果有多个 UI 线程,每个线程都应该有自己的 OSK。我不明白你为什么需要启动其他线程。
  • 我创建的唯一单独线程是其中包含 OSK 的线程,因此它可以与需要文本输入的模式对话框一起使用。其他一切都在原始的主线程上。
  • 您使用的是哪个操作系统(以防万一您使用的是 Mono)?这可能会产生影响。

标签: c# winforms multithreading


【解决方案1】:

我认为这实际上是 Windows 窗体中的一个错误。由于它检查错误线程对 Handle 属性的访问的方式,有些不可避免。 SetParent 的 SDK 文档没有明确说明,它指出要求是两个窗口属于同一个应用程序。没有提到必须属于同一个线程。我知道“相同应用程序”的要求并不难,Windows 中有 appcompat 代码可以让来自不同进程的 Windows 工作。 Adobe Acrobat ab/用了很长时间。这绝对免除了“相同线程”的要求。

好吧,解决问题并尝试一下。在设置所有者之前将 Control.CheckForIllegalCrossThreadCalls 设置为 false,然后再设置为 true。并测试一下。如果您遇到问题,请尝试直接调用 SetParent() 而不是设置所有者。 Windows 窗体实际上使用了 SDK 不推荐的 SetWindowLongPtr。

【讨论】:

    【解决方案2】:

    我会尝试一下。尝试将 OSK 作为单独的进程运行。

    【讨论】:

    • 这个问题是我没有得到拥有的工具窗口的行为,主要是只为窗体的所有者始终在顶部,当主窗体聚焦时,拥有的窗口也在它旁边弹出。
    【解决方案3】:

    尝试将ShowDialog 用于 OSK,而不是 Application.Run - ShowDialog 创建一个消息循环并在窗口关闭时结束它,也许会解决您的问题。

    new Thread(() => new OSK().ShowDialog());
    

    【讨论】:

      【解决方案4】:

      为什么不使用Control.Invoke 进行跨线程调用以避免InvalidOperationException

      【讨论】:

      • 因为主要错误发生在我调用Application.Run时,这是由于OSK的所有者是主窗口引起的。它试图通过将句柄与所有者相关联来做一些内部工作,这会导致跨线程异常。我无法控制它,因为它在 System.Windows.Forms 内。
      • @nasufara:所以你在主窗体中使用Application.Run(new OSK())
      • 我基本上在主窗口的构造函数中做new Thread(() => Application.Run(new OSK())).Start();(还有一些初始化的东西,但它不相关,为了简洁而省略了)。
      • 但是你为什么要做 Application.Run 呢?为什么你的表单需要模态?
      猜你喜欢
      • 1970-01-01
      • 2011-02-26
      • 1970-01-01
      • 2012-09-25
      • 2011-04-25
      • 1970-01-01
      • 1970-01-01
      • 2011-01-15
      • 1970-01-01
      相关资源
      最近更新 更多