/// <summary> /// TRANSACTIONS INSIDE. /// Execute all operators in three steps. /// Also checks host problem, if any, fix and prompt user /// to restart operation. /// </summary> public static void Operation123(Document _doc, IEnumerable <ElementOperator> _ops) { var removers = _ops.Where(x => x is ElementRemover); var nonRemovers = _ops.Where(x => x is ElementRemover == false); var ds = new DialogSuppressor(); string errorMsg = "操作未完成。"; using (Transaction trans = new Transaction(_doc, "preprocess")) { ds.UseInTransaction(trans); trans.Start(); foreach (var op in nonRemovers) { op.PreProcess(); } trans.Commit(); if (trans.GetStatus() != TransactionStatus.Committed) { throw new TransactionNotCommitedException(errorMsg); } } execute: using (Transaction trans = new Transaction(_doc, "execute")) { ds.UseInTransaction(trans); trans.Start(); foreach (var op in nonRemovers) { if (!op.Cancel) { op.Execute(); } } if (FamilyCreator.HostsWithInstanceFaceProblem.Count > 0) { trans.RollBack(); } else { trans.Commit(); if (trans.GetStatus() != TransactionStatus.Committed) { throw new TransactionNotCommitedException(errorMsg); } } } //the geometry face retrieved from it might be in one of two states: //A, directly retrieved from instance. The stable reference string does not contain "INSTANCE", or; //B, retrieved from symbol geometry first, then apply instance transform. The stable reference string contains "INSTANCE". //State B might result in failure of creating new instance on face, even when the line stays //perfectly inside face. //To avoid this problem, a face with state A must be ensured. //A join operation of the host will make sure that faces retrieve from it //will always be in state A. if (FamilyCreator.HostsWithInstanceFaceProblem.Count > 0) { UserMessages.ShowMessage("某些主体图元导致本次操作失败。已修复这些图元,请重新进行操作。"); using (Transaction trans = new Transaction(_doc, "fix")) { ds.UseInTransaction(trans); trans.Start(); foreach (var host in FamilyCreator.HostsWithInstanceFaceProblem) { HostUtils.FixInstanceFaceProblem(host); } trans.Commit(); } } FamilyCreator.HostsWithInstanceFaceProblem.Clear(); using (Transaction trans = new Transaction(_doc, "postprocess")) { ds.UseInTransaction(trans); trans.Start(); foreach (var op in nonRemovers) { if (!op.Cancel) { op.PostProcess(); } } trans.Commit(); if (trans.GetStatus() != TransactionStatus.Committed) { throw new TransactionNotCommitedException(errorMsg); } } //hand and facing need second round of set. var ctrs = nonRemovers .Where(x => x is WallBasedFamilyCreator || x is FaceBasedFamilyCreator).ToList(); if (ctrs.Count > 0) { using (Transaction trans = new Transaction(_doc, "postprocess 2")) { ds.UseInTransaction(trans); trans.Start(); foreach (var ctr in ctrs) { if (!ctr.Cancel) { ctr.PostProcess(); } } trans.Commit(); if (trans.GetStatus() != TransactionStatus.Committed) { throw new TransactionNotCommitedException(errorMsg); } } } //delete elements using (Transaction trans = new Transaction(_doc, "delete")) { trans.Start(); foreach (var op in removers) { op.Execute(); } trans.Commit(); } }