Reloading family symbol fails for the second time

jw.vanasselt
Advocate
Advocate

Reloading family symbol fails for the second time

jw.vanasselt
Advocate
Advocate

Hi all,

I have a problem with (re)loading a family symbol.

// FamilySymbol ophalen vanuit familyName en familytype name
fs = new FilteredElementCollector(doc)
    .OfClass(typeof(FamilySymbol))
    .Cast<FamilySymbol>()
    .FirstOrDefault(x => x.FamilyName == familyName && x.Name == familyTypeName);

CustomFamilyLoadOptions load_options = new CustomFamilyLoadOptions();


// Als niet aanwezig is dan inladen
if (fs == null)
{

    if (!doc.LoadFamilySymbol(familyPath, familyTypeName, load_options, out fs))
    {
        TaskDialog.Show("Error", "Er gaat iets mis met het inladen van de family.");
        fs = null;
    }                        
}
else if(fs != null)
{
    // content versie xml ophalen
    string contentVersieXml = selectedFileData.ContentVersie.Replace("Contentversie: ", "");


    // Contentversie uit symbol halen
    string contVersieFamily = fs.LookupParameter("NLRS_C_content_versie")?.AsString();

    if(contentVersieXml != contVersieFamily)
    {


        bool result = doc.LoadFamilySymbol(familyPath, familyTypeName, load_options, out fs);

        if (!result)
        {
            TaskDialog.Show("Error", "Er gaat iets mis met het (her)inladen van de family.");
            fs = null;
        }
    }


}

 

When I use the debug function, the first familysymbol i try to reload is reloading well.

The parameters are change and everything is fine.


The second family type that I try reload fails, the   result is true but the IFamilyLoadOptions doesn't activate.

 

Here is my IFamilyLoadOptions, the first time the debug is writing this line:
OnFamilyFound _ FamilyInUse: True - overwriteParameterValues True"

 

The second time there is no debug.

/// <summary>
/// Methode hoe de family ingeladen moet worden. 
/// Als family gevonden wordt dan overschrijft de family de parameters.
/// Als Shared family gevonden worden de subcomponenten ook overschrijven.
/// </summary>
[Transaction(TransactionMode.Manual)]
public class CustomFamilyLoadOptions : IFamilyLoadOptions
{
    public bool OnFamilyFound(bool familyInUse, out bool overwriteParameterValues)
    {


        // Als de familie al in gebruik is, beslissen we hier of we deze willen overschrijven of niet.
        // In dit voorbeeld zullen we de familie altijd overschrijven, zelfs als deze in gebruik is.
        overwriteParameterValues = true;
        
        
        Debug.WriteLine($"OnFamilyFound _ FamilyInUse: {familyInUse} - overwriteParameterValues {overwriteParameterValues}");
        return true;
    }

    public bool OnSharedFamilyFound(Family sharedFamily, bool familyInUse, out FamilySource source, out bool overwriteParameterValues)
    {
        // Als een gedeelde familie wordt gevonden, kunnen we hier beslissen of we deze willen laden of niet.
        // In dit voorbeeld zullen we de gedeelde familie altijd laden, zelfs als deze al in gebruik is.
        source = FamilySource.Family;
        overwriteParameterValues = true;

        Debug.WriteLine($"OnSharedFamilyFound _ sharedFamily: {sharedFamily} - familyInUse {familyInUse} - source {source} - overwriteParameterValues {overwriteParameterValues}");

        return true;
    }
}

 

I found this example in the SDK:

RevitSdkSamples/SDK/Samples/FamilyParametersOrder/CS/SortLoadedFamiliesParamsForm.cs at master · jer...

 

@jeremytammik is there a specific reason that this example is creating a temp file?

 

KG 
Jan Willem

0 Likes
Reply
Accepted solutions (1)
770 Views
17 Replies
Replies (17)

jeremy_tammik
Autodesk
Autodesk

I did not read all your code.

   

However, just looking at this line:

   

fs = new FilteredElementCollector(doc)

  

I would assume that the resulting variable fs will never be null, even if the resulting collection is empty. If so, that might explain why the following statement will never be true, and the code in the if-scope will never execute:

   

else if(fs != null)

  

I would suggest always running your dubious code in the debugger to step through it line by line and see what happens.

    

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes

jw.vanasselt
Advocate
Advocate

Thanks for the response @jeremy_tammik 
The fs started as : FamilySymbol fs = null;

 

That's the weird thing, the result is true.

 

jwvanasselt_0-1728647335960.png

 


But the IFamilyLoadOptions is not activated. Is that because the modify date of the family isnt change?

0 Likes

ricaun
Advisor
Advisor

The 'NLRS_C_content_versie' is a type parameter?

 

You are using the LoadFamilySymbol to load a symbol in a existent Family.

 

That's a good questing if the IFamilyLoadOptions should trigger with a FamilySymbol conflict.

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

0 Likes

jw.vanasselt
Advocate
Advocate

@ricaun 

Yes, the parameter is a type parameter.

I try to reload it in a project.

 

The IFamilyLoadOptions doesn't trigger.. i guess because the family is already in the project by the first action, but I reloaded a specific symbol. 

I see a remark on the OnFamilyFound bool, it says should only trigger when family is changed, in this case it isnt ...

 

I tried to create a temp file, but nothing works 

0 Likes

TripleM-Dev.net
Advisor
Advisor

Hi @jw.vanasselt,

 

I haven't looked into the full code, maybe a variable is re-used or something...

 

But keep in mind filtering for a Symbol only using it's familyname and typename CAN return others if the Category isn't taken into account. Familynames across categories can be thesame.

Given that with the typename the chance is low. I never use FirstOrDefault in such case, but test the collector on count = 1 (Or use Single/SingleOrDefault) -> Well not for UserFamilies..So would be relative save as long as they aren't named after system families (A window family "Walls" can exist...)

 

Does the Type come from the family file or a TypeCatalog?

TripleM-Dev.net
Advisor
Advisor

From the documentation:

 

LoadFamilySymbol :

Return Value
True if the family type/symbol was loaded successfully into the project, otherwise False. -> So not sure what happens if the type values are changed in the project but the Family file on disk isn't. -> In the UI this won't trigger a warning and no option to overwrite the values of the family type in the project.

If you change something to the Family File (new type + delete type) it's seen as changed, maybe same for the API version?

 

I would test it out with a small controlled code snipplet (fixed family name, maybe even fixed ID...) in the API and see what it does in each situation + identical test in the UI (Same unchanged family and a updated family from disk).

0 Likes

ricaun
Advisor
Advisor

I'm doing some unit test to understand what is happening, and when loading the same family file the LoadFamily return false even if I change the parameters in the symbols. The LoadFamilySymbol return true but the parameter in the type is not replaced.

 

Looks like the main Family need to be changed in some way to make IFamilyLoadOptions to trigger and replace the parameters.

 

If you change the type parameter and try to load the family again, if is the same file does not seen to replace the parameters. I tried to copy the file, and didn't work. Only if I changed the Family and reload in some way in the project.

 

Here is the test project:

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

0 Likes

TripleM-Dev.net
Advisor
Advisor

And what if it's loaded from another location?

The location a family is loaded from is available in the project, so that should update if loaded from another location....

0 Likes

ricaun
Advisor
Advisor

I tried to copy the file to a different folder and Revit is smart to know that is the same file, is not gonna reload a family that is already loaded.

 

ricaun_0-1728674992656.png

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

0 Likes

jw.vanasselt
Advocate
Advocate

Thanks for building the test @ricaun !

Well that's exactly the thing I need.

I tried it manual with the same result. 

 

The only method I found is to rename the family with _old and reload the new one.

Any other ideas?

0 Likes

jw.vanasselt
Advocate
Advocate

@TripleM-Dev.net 

It is a family type, not a catalog

0 Likes

ricaun
Advisor
Advisor
Accepted solution

Is you rename you gonna need to find all the instances and replace with the new family, and could be some reference you could forget to swap.

 

Another way would be to open the family changed something without changing and reload in the document. The next time you try to load the same family should be different and IFamilyLoadOptions trigger and the type parameter is replaced.

 

This code force to open the family, change the current type name and rollback, and load back in the document.

FamilyUtils.EditLoadFamily(document, FamilyUtils.SelectFamily(document, FamilyName), (familyDocument) =>
{
    using (Transaction transaction = new Transaction(familyDocument))
    {
        transaction.Start("Change Family");

        var name = familyDocument.FamilyManager.CurrentType.Name;
        familyDocument.FamilyManager.RenameCurrentType(name + $" {DateTime.UtcNow.Ticks}");
        familyDocument.FamilyManager.RenameCurrentType(name);

        transaction.Commit();
    }
});

 

The only problem could be if you have a big document and this could take a while to regenerate the document after reload the family.

 

Here is the FamilyUtils class:

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

jw.vanasselt
Advocate
Advocate

That's a nice one will try at monday!

jw.vanasselt
Advocate
Advocate

@ricaun 

This example has been edited, if I see correctly the family from the project?

 

I have the changed family in a central environment, with this action he will open and reload the current one (in the project). But the symbol that is present in the project is outdated and cannot be orderded.
Or did I miss a line of code?

0 Likes

jw.vanasselt
Advocate
Advocate

Got it!
Forgot to reload the Family Symbol first before edit that family 🙂

Thanks alot!

TripleM-Dev.net
Advisor
Advisor

Depending on Family (and number of) doesn't this add a huge amount of time to update a family, seems a bit overkill?

 

If the family from disk and in project is detected by Revit as identical, why not retrieve the type values of the Disk Family by opening it in the background, reading it's type values of the needed type and push those back into the project.

 

And better even, if a TypeCatalog is used (or a cached dataset of the values) the updating would be even quicker. (as you are already doing with the ContentVersion XML)

 

Btw; if the ContentVersion is different shouldn't the family be different, and LoadFamilySymbol work, or can this also refer to changes in parameter values? And in that case (if only a parameter value is changed) does LoadFamilySymbol then also not work/overwrite?

 

Just wondering what the use case is for this?

- Michel

 

Ps. I have several tools that push data into the model elements based on some criteria outside or in the model, but I only push data that's different and the user gets notification of x-items changed (and which), so to reduce access to elements in regards to worksharing/ownership and time. My advise is; only overwrite what's needed.

jw.vanasselt
Advocate
Advocate

That's a good point, and I will definitely look into it. Do you have any examples you could share to demonstrate how you are handling this in your tools? It would be helpful to see how you manage pushing only the necessary data.

 

Kind Regards,
Jan Willem

0 Likes