前言
UI講完,回到DB
這塊兒。在Document那篇,提到增刪改查操作都是在Document上,是對Documet進行操作。
看到“增刪改查”這四個,想到什么了沒有?
數據庫(DB)嘛~話說那本經典的紅皮數據庫的書叫啥來著?算了算了,數據庫也忘得差不多了😶。
回到Revit API,“刪”我們在Document那篇就講過了,用Delete方法就行了。“查”就是過濾器,上篇的選擇器也能沾一點兒邊。還有“增”和“改”這倆個。
數據庫中的“增”,是增加新的數據,對應Revit就是增加新模型、創建新實例,我們將會在涉及到Creation
時講。
數據庫中的“改”,是對原有數據進行修改。在Revit中,就比較寬泛了,或許應該稱之為“變化”,變化了就是改了。這塊兒,體現在事件上,后面專門些一篇關于Events
的,再提改這部分。
回到本篇。
在數據庫中,有事務的概念,Revit 的這個功能上差不多,但沒有那么細致。
這篇,涉及的主要類如下圖
一、Transaction(事務)
其實在第一篇Namespace與Attributes中,就提到事務,只是那會兒沒有展開。
[Transaction(TransactionMode.Manual)] // 開啟事務
現在我們開始講事務。
Revit的事務是做什么的,當我們要進行的操作會改變Document時,就必須在事務中進行,比如:刪除元素,調整元素參數,設置元素顯影。
Revit中,事務類有3個,分別是:
Transaction
:事務TransactionGroup
:事務組,可以在事務組里創建新的事務SubTransaction
:子事務,必須在事務中,子事務可嵌套
1.1. 三種事務的對比
來看看方法對比
Transaction | TransactionGroup | SubTransaction |
---|---|---|
Start(..) x2 | Start(..) x2 | Start |
Commit(..) x2 | Assimilate Commite | Commite |
RollBack(..) x2 | Rollback | Rollback |
Dispose | Dispose | Dispose |
Get/SetName | Get/SetName | – |
GetStatus HasStarted HasEnded | GetStatus HasStarted HasEnded | GetStatus HasStarted HasEnded |
GetFailureHandlingOptions SetFailureHandlingOptions | – | – |
差異:事務名稱,故障處理 | 差異:事務組名稱,打包提交 | |
瞧,就這么丟丟的差異。
事務:可以在事務上添加故障處理程序。
事務組:可以將多個事務組織成一個事務提交(Assimilate
),也可一次性提交(Commite
)。
子事務:只能在事務中開啟,本身可嵌套。沒自己的名稱。
1.2. 事務組的2種提交方式
事務組兩種提交方式的區別。
對于下面的代碼,將事務改為子事務,事務組改為事務,也是可以的。
public void TestTransactionGroup(UIDocument uIDoc)
{View view = uIDoc.ActiveView;List<ElementId> wallIds = this.GetElementByCategory(uIDoc.Document, BuiltInCategory.OST_Walls);wallIds = wallIds.Take(5).ToList(); // 取5個// 事務組using (TransactionGroup transactionGroup = new TransactionGroup(uIDoc.Document, "TransactionGroup-隱藏-所有墻體")){transactionGroup.Start();foreach (ElementId wallId in wallIds){// 事務using (Transaction transaction = new Transaction(uIDoc.Document, $"Transaction-隱藏-{wallId.IntegerValue}")){transaction.Start();view.HideElements([wallId]);transaction.Commit();}}//transactionGroup.Assimilate(); // 將5個事務打包成一個,提交transactionGroup.Commit(); // 5個事務一次性提交,還是5個}
}
1.3. 子事務
上面說了,子事務必須要在事務中才能創建,不然就會報錯。
子事務一般在什么時候使用呢?一般是作為獨立的小的操作步驟,插入到有具體業務的事務的邏輯中。
但有時我們需要進行一些操作了,卻不能確定當前是否在事務中呢?
這個問題是有意義的,因為事務是不可嵌套的,我們無法在一個事務中開啟另一個事務,又無法在非事務中創建子事務,所以需要根據當前的狀態,來選擇性處理。
還記Document的IsModified
屬性嗎,True
表示文檔正處于修改中,也就是已開啟了事務。
使用
document.IsModified
來判斷當前事務環境。
根據環境不同,來決定是創建 事務 還是 子事務
二、Failures(故障處理)
事務執行失敗了怎么辦?我們可以回滾Rollback
。
不想回滾呢?那就try-catch處理問題吧。
但這里的說的故障處理可不是程序上的錯誤,而是Revit發出的問題。
Revit里有許多的約束,當文檔變化時,就會進行校驗,判斷是否允許更改,常見的問題有“不滿足約束”“無法剪切圖元”等,在遇到這些問題時,Revit會有彈框,并暫定程序的執行,待用戶選擇操作后才會繼續處理。
這種由Revit發出的警告或錯誤,是無法通過try-catch處理的,得提供專門的故障處理方式,即實現IFailuresPreprocessor
接口,并將其提供給事務。
2.1. IFailuresPreprocessor
IFailuresPreprocessor
需要實現一個方法,也只有這個方法。
public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor)
方法有個參數FailuresAccessor
,文檔中是這么介紹的:“是獲取文檔故障信息的唯一可以接口,雖然可以在故障處理期間讀取文檔,但在處理期間修改文檔的唯一方法是通過此類提供的方法”。
但在我的測試中,拿到Document進行一些操作,沒有效果也不報錯,不明白🙃。
甚至只要我在故障處理方法力稍稍做些事兒,錯誤彈框就無法被跳過,還是會彈出來。
類成員,就不列了。
2.2. 取消Revit 警告/錯誤 彈框
注意,錯誤不應該直接ResolveFailure
,Revit可能會采用刪除的方式處理。
internal class MyFailuresPreprocessor : IFailuresPreprocessor
{public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor){IList<FailureMessageAccessor> failures = failuresAccessor.GetFailureMessages();foreach (FailureMessageAccessor failure in failures){//ICollection<ElementId> additionalElements = failure.GetAdditionalElementIds(); // 獲取與問題相關的其他元素//ICollection<ElementId> failingElementIds = failure.GetFailingElementIds(); // 獲取引起問題的元素FailureSeverity failureSeverity = failure.GetSeverity(); // 獲取失敗的嚴重程度if (failureSeverity == FailureSeverity.Warning){failuresAccessor.DeleteWarning(failure); // 刪除警告}else if (failureSeverity == FailureSeverity.DocumentCorruption){return FailureProcessingResult.ProceedWithRollBack; // 文檔損壞,回滾}else if (failureSeverity == FailureSeverity.Error){//FailureDefinitionId failureId = failure.GetFailureDefinitionId(); // 獲取失敗的定義ID//if (failureId == BuiltInFailures.CutFailures.CannotCutInstanceOut) // 如果問題是無法剪切實例//{// failure.SetCurrentResolutionType(FailureResolutionType.MoveElements); // 嘗試采用移動物體的方式處理//}failuresAccessor.ResolveFailure(failure); // 解決錯誤}}return FailureProcessingResult.ProceedWithCommit; // 提交 // 可能會刪除部分模型//return FailureProcessingResult.Continue;}
}
上面的代碼,會不顯示所有的警告彈框。對于下面的錯誤彈框,也會消失。
當然,這不意味著就可以剪切了,具體的效果就是取消了剪切。
三、通過代碼進行歷史操作回退
在Revit左上角快捷欄里,有事務歷史,我們當然可以通過交互的方式快速回退到之前的文檔。其實這個操作也是可以通過代碼進行的。
我們需要引入庫UIFrameworkServices.dll
,其中有類QuickAccessToolBarService
。
// 找到歷史操作記錄
public static ObservableCollection<string> collectUndoRedoItems(bool bForUndo);// 回退或前進,步數
public static void performMultipleUndoRedoOperations(bool bForUndo, int iNumOperations)
總結
寫到這兒,一看最上方的導圖,好像還有個事件,算了,不寫了🙄。