一.起因
自己在寫revit二開時,有一個Winform窗體按鈕點擊事件需要 觸發調用事務進行處理,結果出現“異常“Starting a transaction from an external application running outside of API context is not allowe“”
其實這是 上面異常是Revit的一種保護機制,創建的非模態對話框Form1后,在Form1未關閉的狀態下,Revit認為是處於非API的上下文環境,所以異常彈出來了。
在非模態對話框打開的狀態下,調用Transaction必須通過Idling或者ExternalEvent API進行相關代碼調用;在SDK Sample安裝包下面,有個例子程序叫ModelessDialog詳細介紹了Idling及ExternalEvent的調用機制。
在Revit 2014之前的版本,當非模態對話框打開的狀態,調用Transaction是可以的,但是從Revit 2014之后因為考慮安全等方面被禁止了。
二.解決辦法與代碼
非模態窗口有一個好處,就是可以一直停留在程序之前,然后持續完成操作。但是在Revit二次開發中,非模態窗口也有幾個注意事項。
1、需要在文檔關閉的時候,把非模態窗口也關閉掉,不然會導致文檔關閉,窗口還在這樣奇怪的Bug。
2、非模態的窗口的事件需要在IExternalCommand里注冊。
3、每個操作必須在外部事件里進行。
2.1 第一步:注冊外部事件

2.2 第二步:Form內使用

在Form構造函數或者Load事件內:

我Form窗體內有一個TreeList控件,控件鼠標點擊事件觸發 外部事件:

GetSelectedDistributionProLevel()為獲取當前TreeList鼠標選中的Node信息,DistributionProjectLevelData為自己定義的Class
m_elecGridLayingOpe.SetGridLineElementSelected(app, node.LevelUniqueID)里面的代碼如下:

其中UniqueId為Element的UniqueId.
三.焦點(關鍵點)
在Revit二次開發中,如果使用了非模態窗體,設置好參數輸入后,點擊按鈕命令后,Revit沒有立刻進入到激活狀態,當前的窗體仍然是非模態窗體。以前我會在點擊按鈕中加入一句:this.Close(),直接關閉非模態窗體,這種方式太粗暴。
究其原因:在做的非模態窗體在執行相應命令后,窗體並沒有關閉或是隱藏,就一直處於激活狀態,導致Rveit不能立刻激活或者取到焦點。解決辦法:使用WindowsAPI下的兩個函數 GetActiveWindow(),SetActiveWindow(IntPtr hwnd),一個是獲得當前系統獲得焦點的窗體句柄,一個是設置當前系統某個窗體獲得焦點。
為獲得Rveit的窗體句柄,需要添加引用:AdWIndows.dll
代碼如下:

在Form構造函數內:

在TreeList鼠標點擊事件函數內:

