Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#-可以在单独的线程中安全地拥有自己的表单吗?_C#_Winforms_Multithreading - Fatal编程技术网

C#-可以在单独的线程中安全地拥有自己的表单吗?

C#-可以在单独的线程中安全地拥有自己的表单吗?,c#,winforms,multithreading,C#,Winforms,Multithreading,我正试图为一个用C#编写的应用程序编写一个专用的屏幕键盘(OSK)。为了方便起见,我创建了一个表单,表单上有几个表示键的按钮,单击这些按钮可以调用SendKeys,并发送相应的键 此表单由应用程序首次启动时显示的主窗口所有,使用Owner属性。这样,只要用户关注应用程序,OSK就会弹出,如果说主窗口被拖到它上面,它就会停留在主窗口的顶部 这一切都很好,但因为我有模式对话框,我也想在OSK中使用,所以我尝试在一个单独的线程中创建它,并完成它自己的消息循环(通过应用程序。运行),这样它仍然可以与主线

我正试图为一个用C#编写的应用程序编写一个专用的屏幕键盘(OSK)。为了方便起见,我创建了一个表单,表单上有几个表示键的按钮,单击这些按钮可以调用
SendKeys
,并发送相应的键

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

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

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

我的问题是,是否有可能在一个线程上以安全的方式拥有一个独立于所有者的表单?如果不能做到这一点,是否有可能模拟拥有表单的特征(即仅主窗口始终位于顶部,主窗口聚焦时弹出)


谢谢,如果这让人困惑,请道歉。

为什么不使用跨线程调用来避免
InvalidOperationException

我要试试看。尝试将OSK作为一个单独的进程运行。

尝试对OSK使用
ShowDialog
,而不是
应用程序。运行
-
ShowDialog
创建一个消息循环,并在窗口关闭时结束它,可能会解决您的问题

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

我认为这实际上是Windows窗体中的一个bug。由于它检查错误线程对句柄属性的访问的方式,这是不可避免的。SetParent的SDK文档对此没有明确说明,它声明要求两个窗口属于同一个应用程序。没有提到必须属于同一条线。我知道“同一个应用程序”的要求并不难,Windows中的appcompat代码使它在不同进程的Windows中工作。Adobe Acrobat ab/长期使用此功能。这绝对免除了“同一线程”的要求


好吧,把这个问题扔出去试试。在设置所有者之前,将Control.CheckForIllegalCrossThreadCalls设置为false,之后将其设置为true。然后测试一下。如果遇到问题,请直接尝试pinvoking SetParent(),而不是设置所有者。Windows窗体实际上使用的是SDK不推荐的SetWindowLongPtr。

为什么要在单独的UI线程中使用模式对话框?似乎如果有多个UI线程,每个线程都应该有自己的OSK。我不明白你为什么需要启动其他线程。我正在创建的唯一一个单独的线程是带有OSK的线程,这样它就可以与需要文本输入的模式对话框一起使用。其他一切都在原始的主线程上。您使用的是哪个操作系统(以防您使用Mono)?这可能会产生影响。因为主要错误发生在我调用
Application.Run
时,这是由于OSK的所有者是主窗口造成的。它试图做一些内部工作,将句柄与所有者关联起来,这会导致交叉线程异常。我无法控制它,因为它在
System.Windows.Forms
@nasufara:所以你在主窗体中使用
Application.Run(new OSK())
?我基本上做
new Thread(()=>Application.Run(new OSK()).Start()在主窗口的构造函数中(还有一些初始化的东西,但它并不相关,为了简洁起见被省略了)。但是为什么要运行应用程序呢?为什么需要将表单设置为模态?问题是我不了解所拥有的工具窗口的行为,主要是对于表单的所有者而言始终处于顶部,并且当主表单处于焦点时,所拥有的窗口也会随之弹出。