2010-09-26 63 views
4

我正在嘗試爲我在C#中編寫的應用程序編寫專門的屏幕鍵盤(OSK)。爲了實現這一點,我創建了一個表單,其上有幾個表示鍵的按鈕,並單擊它們調用SendKeys併發送相應的鍵。C# - 可以安全地擁有一個獨立的線程擁有的形式?

此表格由應用程序第一次啓動時顯示的主窗口所有,使用Owner屬性。這樣,只要用戶關注應用程序,OSK就會彈出,如果主窗口被拖動到主窗口上,OSK就會保持在主窗口的頂部。

這一切都很好,但因爲我有模式對話框,我也想用OSK,我試圖在一個單獨的線程中創建它,並使用它自己的消息循環(通過Application.Run),所以它仍然可以可用於主線程中的任何模態對話框。

這樣做的問題在於,顯然,由於跨線程調用,在單獨的線程中可能導致InvalidOperationException。其中一個具體示例是,在從新線程調用Application.Run(osk)時,會發生交叉線程錯誤,因爲它正嘗試用所有者(主窗口)更新窗口句柄。

我的問題是,是否有可能在一個線程上擁有一個獨立於所有者的安全方式?而且,如果失敗了,是否有可能模仿擁有的表單的特性(即只有主窗口始終處於頂部,並在主窗口關注時彈出)?

謝謝,抱歉,如果這是混亂。

+0

爲什麼要在不同的UI線程中使用模態對話框?看起來如果有多個UI線程,每個線程應該有它自己的OSK。我不明白你爲什麼需要啓動其他線程。 – YWE 2010-09-26 03:23:30

+0

我創建的唯一獨立線程是OSK中的線程,因此它可以用於需要文本輸入的模式對話框。其他一切都在原始主線程上。 – mgbowen 2010-09-26 03:25:14

+0

好的,這是有道理的。 – YWE 2010-09-26 03:35:58

回答

2

我認爲這實際上是Windows窗體中的一個錯誤。由於它檢查通過錯誤線程訪問Handle屬性的方式有點不可避免。 SetParent的SDK文檔沒有詳細說明它,它表示要求是兩個窗口屬於同一個應用程序。沒有提及必須屬於同一個線程。我知道「同樣的應用程序」要求並不難,Windows中有一些appcompat代碼,它可以用於來自不同進程的windows。 Adobe Acrobat ab /使用了很長時間。這絕對免除了「同一線程」的要求。

好吧,解決這個問題並嘗試一下。將Control.CheckForIllegalCrossThreadCalls設置爲false,然後再將其設置爲true。並測試一下它。如果遇到問題,請嘗試直接調用SetParent()而不是設置Owner。 Windows窗體實際上使用了SDK不推薦的SetWindowLongPtr。

+0

聽起來不錯。你最終使用了什麼? – 2010-09-27 16:01:10

0

爲什麼不使用Control.Invoke進行跨線程調用以避免InvalidOperationException

+0

由於主要錯誤發生在我調用'Application.Run'時,這是由OSK的所有者爲主窗口引起的。它試圖通過將句柄與所有者相關聯來做一些內部的事情,並導致一個交叉線程異常。我無法控制它,因爲它在'System.Windows.Forms'內。 – mgbowen 2010-09-26 03:29:03

+0

@nasufara:那麼你在主窗體中使用'Application.Run(new OSK())'? – 2010-09-26 03:40:33

+0

我基本上在主窗口的構造函數中執行'new Thread(()=> Application.Run(new OSK())).Start();'這裏有一些更多的初始化的東西,但它不相關,爲簡潔起見)。 – mgbowen 2010-09-26 03:43:27

1

我會對此進行一次刺探。嘗試將OSK作爲單獨的進程運行。

+0

這樣做的問題是我沒有獲得擁有的工具窗口的行爲,主要是窗體的所有者總是在最上面,當主窗體關注時,擁有的窗口也會彈出。 – mgbowen 2010-09-26 03:45:20

1

嘗試使用ShowDialog作爲OSK而不是Application.Run - ShowDialog創建一個消息循環並在窗口關閉時結束它,並且可能會解決您的問題。

new Thread(() => new OSK().ShowDialog()); 
相關問題