ワークセット内の要素の編集

概要

チームで作業する場合、単一のユーザの場合には発生しない、Revit API アドインの操作性の問題が発生することがあります。特に、アドインの設計方法によって、編集の競合が回避できることもあれば発生することもあります。たとえば、アドインが何千もの要素の編集を行おうとした場合、これらの要素すべてをローカル ユーザにチェックアウトする必要があり、中央との同期が完了するまで、他のユーザはそれらの要素を使用できなくなります。または、要素のいくつかが他のユーザにチェックアウトされていて、編集できない場合があります。ワークシェアリングされたモデルに API から変更を加える場合は、この点に注意する必要があります。

基本的なモデル編集ワークフローは次のようになります。

操作 重要である理由
ユーザがモデルの一部の要素を変更します ユーザが壁をドラッグします これらの変更は「ユーザによる変更」となります。ユーザが変更を加えるには、これらの要素を借用する必要があります。
Revit は必要に応じて、モデルに追加のデータを再生成します 結合された壁が移動され、床が更新され、屋根が更新され、部屋が更新され、部屋タグはそれらが部屋に残っているかどうかをチェックします これらの変更は「システムによる変更」となります。変更された場合でも、他のユーザはそのまま使用できます。

ほとんどの API の変更は「ユーザによる変更」であり、ローカル ユーザが手動で変更を加えた場合と同様に処理されます。外部コマンド、マクロ、イベントからの呼び出しの場合にこのように処理されます。唯一の例外はアップデータから行われた変更であり、これはシステムによる変更として扱われます。

要素の所有権

ワークシェアリングされたドキュメント内の要素を編集しようとした際に発生するワークシェアの問題に対処する方法の 1 つとして、要素の編集に使用するトランザクションに FailureHandlingOptions を設定する方法があります。こうすることで、下に示すように、編集のエラーを自動的に捕捉して抑止でき、変更をロールバックすることができます。

コード領域: ワークシェアリング エラーを抑止

public static void TryToEditGeometricElement(Element elem, bool useFailureHandlingOpts)
{
    Document doc = elem.Document;
    using (Transaction t = MakeTransaction(doc, "Move element", useFailureHandlingOpts))
    {
        t.Start();
        ElementTransformUtils.MoveElement(doc, elem.Id, new XYZ(1, 1, 0));
        t.Commit();
    }
}

private static Transaction MakeTransaction(Document doc, string name, bool useFailureHandlingOpts)
{
    Transaction t = new Transaction(doc, name);
    if (useFailureHandlingOpts)
    {
        FailureHandlingOptions opts = t.GetFailureHandlingOptions();
        opts.SetClearAfterRollback(true);
        opts.SetFailuresPreprocessor(new WorksharingErrorsPreprocessor());
        t.SetFailureHandlingOptions(opts);
    }

    return t;
}

WorksharingUtils クラスを使用すると、要素とワークセットの所有権を修正できます。CheckoutElements()メソッドは、できるだけ多くの指定した要素の現在のユーザに所有権を取得し、CheckoutWorksets()メソッドはワークセットに対して同じ処理を行います。これらのメソッドは、編集を実行する前に要素をチェックアウトするのに役立ちます。RelinquishOwnership()メソッドは、指定された RelinquishOptions に基づいて、現在のユーザによって所有されている要素とワークセットを放棄します。

パフォーマンスを最適化するには、多数の細かな呼び出しではなく、一度の大きな呼び出しですべての要素やワークセットをチェックアウトし、項目を破棄します。

注: 要素をチェックアウトすると、要求された要素を編集可能とするために必要な追加の要素がチェックアウトされる場合があります。たとえば、要素がグループ内にある場合、Revit はグループ全体をチェックアウトします。

次の例では、編集前に特定の要素のチェックアウトを試み、問題が発生した場合に、ユーザに対してメッセージを発行します。

コード領域: 要素をチェックアウト

public static bool AttemptToCheckoutInAdvance(Element element)
{
    Document doc = element.Document;
    String categoryName = element.Category.Name;
            
    // Checkout attempt
    ICollection<ElementId> checkedOutIds = WorksharingUtils.CheckoutElements(doc, new ElementId[] { element.Id });

    // Confirm checkout
    bool checkedOutSuccessfully = checkedOutIds.Contains(element.Id);

    if (!checkedOutSuccessfully)
    {
        TaskDialog.Show("Element is not checked out", "Cannot edit the " + categoryName + " element - " +
                        "it was not checked out successfully and may be checked out to another.");
        return false;
    }

    // If element is updated in central or deleted in central, it is not editable
    ModelUpdatesStatus updatesStatus = WorksharingUtils.GetModelUpdatesStatus(doc, element.Id);
    if (updatesStatus == ModelUpdatesStatus.DeletedInCentral || updatesStatus == ModelUpdatesStatus.UpdatedInCentral)
    {
        TaskDialog.Show("Element is not up to date", "Cannot edit the " + categoryName + " element - " +
                        "it is not up to date with central, but it is checked out.");
        return false;
    }

    return true;
}

次の例は、すべてのビュー ワークセットをチェックアウトする方法を表しています。

コード領域: ワークセットをチェックアウト

void CheckoutAllViewWorksets(Document doc)
{
    FilteredWorksetCollector collector = new FilteredWorksetCollector(doc);

    // find all view worksets
    collector.OfKind(WorksetKind.ViewWorkset);
    ICollection<WorksetId> viewworksets = collector.ToWorksetIds();
    ICollection<WorksetId> checkoutworksets = WorksharingUtils.CheckoutWorksets(doc, viewworksets);
    TaskDialog.Show("Checked out worksets", "Number of worksets checked out: " + checkoutworksets.Count);
}