Rhino.Inside-Revit and Revit Project Browser Refresh

Hi folks,
I am trying to create a Rhino plugin running inside of Rhino.Inside-Revit to convert Rhino Block Instances to Revit families. After testing, the family shows up perfectly in the viewport, but there is no where to find it in the Revit Project Browser panel. Although I had confirmed the family was successfully created in the backend.

Meanwhile, I tried to use the Family-New component in Rhino.Inside-Revit Grasshopper and the Revit Project Browser responded instantly. Amazing - but I cannot find any clue in the doc here:
Rhino.Inside-Revit-Family-New on Github

So - what is causing Revit ignoring the new family and why? What is the secret sauce in the Rhino.Inside-Revit Grasshopper?

Please let me know if you need more info, and thank you in advance for any constructive comments. Looking forward to seeing response from @kike @kike-asuni or anyone who is great in Rhino.Inside and Revit API!

(The revit version is 2024.3, Revit API version is 24.3.30.0. Rhino.Inside version 1.32.9327.20567.)

Best,
Yiliang

Screenshot and code attached here:

// -- build the family document -------------------------------------------------
var famDoc = revitApp.NewFamilyDocument(templatePath);

using (var t = new Transaction(famDoc, "Build geometry"))
{
    t.Start();
    foreach (var s in solids)
        FreeFormElement.Create(famDoc, s);

    if (famDoc.FamilyManager.Types.Size == 0)
        famDoc.FamilyManager.NewType("Default");
    t.Commit();
}

// -- load the family into the current project ----------------------------------
var hostDoc = Revit.ActiveUIDocument.Document;
Family loadedFamily;

loadedFamily = famDoc.LoadFamily(hostDoc, new SimpleFamilyLoadOptions());
famDoc.Close(false);

FamilySymbol symbol =
    hostDoc.GetElement(loadedFamily.GetFamilySymbolIds().First()) as FamilySymbol;
using (var t = new Transaction(hostDoc, "Rename family"))
{
    t.Start();
    symbol.Activate();
    try { loadedFamily.Name = familyName; } catch { }
    try { symbol.Name = familyName; } catch { }
    FamilyInstance instance = hostDoc.Create.NewFamilyInstance(
        new XYZ(0, 0, 0),
        symbol,
        DB.Structure.StructuralType.NonStructural);
    hostDoc.Regenerate();
    t.Commit();
}

Try loading family inside the transaction

tx.Start();
loadedFamily = famDoc.LoadFamily(hostDoc, new SimpleFamilyLoadOptions())
tx.Commit();

Hi,
Thank you for the response!
I’ve tried this before, but got this message:
The document must not be modifiable before calling LoadFamily. Any open transaction must be closed prior the call.
It seems like I cannot use transaction to load the model.

Looking forward to your reply!

Like this not separate transaction

using (var t = new Transaction(hostDoc, “Rename family”))
{
t.Start();

loadedFamily = famDoc.LoadFamily(hostDoc, new SimpleFamilyLoadOptions());
famDoc.Close(false);

FamilySymbol symbol =
hostDoc.GetElement(loadedFamily.GetFamilySymbolIds().First()) as FamilySymbol;

symbol.Activate();
try { loadedFamily.Name = familyName; } catch { }
try { symbol.Name = familyName; } catch { }
FamilyInstance instance = hostDoc.Create.NewFamilyInstance(
    new XYZ(0, 0, 0),
    symbol,
    DB.Structure.StructuralType.NonStructural);
hostDoc.Regenerate();
t.Commit();

}

Unfortunately, it doesn’t change the result…

I assume you are in another command , this command needs to stop first before starting a new transaction, likely the RIR is being considered as a new command.

That is an interesting point - if you see RIR as a command, then this is indeed inside of it.

Although, if you look at my code at the uppermost post, this family loading is outside of a Transaction and it won’t trigger error like the one Muhammad suggested.

are you calling this within a C# node in GH? or are you compiling a new tool natively, I think RIR combine all the nodes within a single DB.TransactionGroup.

can you share a screenshot of the GH canvas?

Love to! I am running in a Rhino-based plugin without using Grasshopper. Here is the .cs file for testing this command. (You can find everything I described in the CreateFamilyFromSolids method)
Thank you!

Cmd_NatProto.cs (6.7 KB)

1 Like

can you put these into a single transaction? or a transaction group?

Additionally, try using before starting a new transaction.
TransactionManager.Instance.ForceCloseTransaction()

this using the namespaces below

using RevitServices.Transactions;
using RevitServices.Persistence;

Unfortunately it is still not working…I tried both Transaction and Transaction Group wrapping. :melting_face:
I’ll try to dig deeper into RIR to see if there are something I was missing.

BTW, I wonder if you have seen this dialog somewhere - my code triggers this open, but no matter which button I click, I won’t see this in the same Windows session.

this is a very common Error / exception within the revit software. I would suggest to debug your code, I am a pyrevit person, so I either use logger or a simple print statements on the output window to find out what went wrong.

Thanks!

I ended up solving this issue by using another thread - not what I planned to do, but it works in an unexpected way.

            ExternalRunner.Instance.RunAsync(app =>
            {
                var doc = app.ActiveUIDocument.Document;

                using (var t = new TransactionGroup(doc, "Populate family"))
                {
                    t.Start();

                    FamilySymbol symbol = CreateFamilyFromSolids(Revit.ActiveUIApplication.Application, solids, blockName);
                    BakeFamiliesToRevit(insertionPoints, rotation, doc, symbol);

                    t.Assimilate();
                }
            });
1 Like

That’s a good solution; it is way above my cognitive ability.

1 Like

Hi @yiliang,

ExternalRunner.Instance.RunAsync is asynchronous, if you need something synchronous and without referencing any Dynamo assembly please try this.

using RhinoInside.Revit;
using ARDB = Autodesk.Revit.DB;

ARDB.FamilySymbol PopulateFamily(IEnumerable<Point3d> points, double rotation, string blockName, IEnumerable<Brep> solids)
{
  return Rhinoceros.InvokeInHostContext(() =>
  {
    var doc = Revit.ActiveUIDocument.Document;

    using (var t = new ARDB.TransactionGroup(doc, "Populate family"))
  
    t.Start();

    ARDB.FamilySymbol symbol = CreateFamilyFromSolids(doc.Application, solids, blockName);
    BakeFamiliesToRevit(insertionPoints, rotation, doc, symbol);

    t.Assimilate();
  
    return symbol;
  });
}

1 Like

Oh that is even better! Thank you Kike

@kike I found an interesting glitch when using your Rhinoceros.InvokeInHostContext approach:

It works perfectly when the caller is a command. However, if I create a UI button and hook it up with this:

RhinoApp.RunScript("_ExportToRevit", false);

It throws an error saying “Starting a transaction from an external application running outside of API context is not allowed.”
Have you experienced this before?