Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Unloading worksets from linked models

8 REPLIES 8
SOLVED
Reply
Message 1 of 9
will.wydock
1274 Views, 8 Replies

Unloading worksets from linked models

Hi,

 

I am writing a routine that would unload 3 worksets from our linked models. Based on everything I have found online, I believe I written this correctly. However everytime i run this routine nothing appears to happen. The only thing I can think of that would be limiting me is how i filter down to just those names that is the issue. I have never tried to write anything that is accessing inside a linked model.

 

public void unloadlinkwrkst(UIApplication uiapp, Document doc)
        {
            Autodesk.Revit.ApplicationServices.Application app = uiapp.Application;

            try
            {

                List<Element> lstRvtLinkType = new FilteredElementCollector(doc).OfClass(typeof(RevitLinkType)).ToList();

                foreach (Document _linkdoc in app.Documents)
                {
                    if (!_linkdoc.IsLinked)
                        continue;
                    RevitLinkType _RvtLinkType = null;

                    foreach (Element elmnt in lstRvtLinkType)
                    {
                        _RvtLinkType = elmnt as RevitLinkType;
                        if (_RvtLinkType.Name != _linkdoc.Title)
                            continue;
                        else
                            break;
                    }

                    List<WorksetId> lstWkSet_Close = new List<WorksetId>();

                    WorksetConfiguration wk = new WorksetConfiguration();
                    ModelPath _modelpath = _linkdoc.GetWorksharingCentralModelPath();
                    WorksetTable _worksetTable = _linkdoc.GetWorksetTable();
                    IList<WorksetPreview> lstPreview = WorksharingUtils.GetUserWorksetInfo(_modelpath);

                    foreach (WorksetPreview item in lstPreview)
                    {
                        Workset wkset = _worksetTable.GetWorkset(item.Id);
                        if (!wkset.IsOpen)
                        {
                            if ((item.Name.CompareTo("Shared Levels and Grids") == 0) || (item.Name.CompareTo("1/4 SCOPEBOX AND MATCHLINE") == 0) || (item.Name.CompareTo("1/8 SCOPEBOX AND MATCHLINE") == 0))
                            {
                                lstWkSet_Close.Add(item.Id);
                                continue;
                            }
                        }
                    }
                    wk.Close(lstWkSet_Close);
                    _RvtLinkType.LoadFrom(_modelpath, wk);
                }

            }
            catch (Exception e)
            {
                TaskDialog.Show("dd", e.Message);
                return;
            }
            return;
        }
8 REPLIES 8
Message 2 of 9
stever66
in reply to: will.wydock

I can't get it to work either and its driving me crazy.   

 

I threw in some task dialog boxes so we can follow the program as it runs. (I'm not very good with the debugger.)

 

I also believe the 

if (!wkset.IsOpen)

should be

if (wkset.IsOpen)

Otherwise, 1stWkSet_Close becomes a list of the worksets that are already closed.

 

I also simplified your compare where it looks for certain worksets.  The program seems to do everything right, but the one line 

wk.Close(lstWkSet_Close);

just doesn't seem to do anything.  I also tried it inside a transaction.  

 

The odd thing is that this line of code actually opens a closed workset.  That doesn't make sense because it is not even including that workset name in the list of worksets.  Seems like a big clue, but I don't get it.

 

Here is what I have, and its still driving me crazy;

 

 

List<Element> lstRvtLinkType = new FilteredElementCollector(doc).OfClass(typeof(RevitLinkType)).ToList();
    		

            //foreach (Document _linkdoc in app.Documents)
                foreach (Document _linkdoc in doc.Application.Documents)
                {
                    
                	TaskDialog.Show("Starting to check Document:", _linkdoc.PathName.ToString());
                	if (!_linkdoc.IsLinked)
                	{
                		TaskDialog.Show("Revit","Continue");
                		continue;
                	}
                	TaskDialog.Show("Revit", "setting Linked type to null");
                	
                	RevitLinkType _RvtLinkType = null;

                    foreach (Element elmnt in lstRvtLinkType)
                    {
                    	TaskDialog.Show("Starting to Check Revit Link:", elmnt.Name.ToString());
                    	
                    	_RvtLinkType = elmnt as RevitLinkType;
                        if (_RvtLinkType.Name != _linkdoc.Title)
                            continue;
                        else
                            break;
                    }
					TaskDialog.Show("Revit","Start processing linked workset");
                    List<WorksetId> lstWkSet_Close = new List<WorksetId>();

                    WorksetConfiguration wk = new WorksetConfiguration();
                    ModelPath _modelpath = _linkdoc.GetWorksharingCentralModelPath();
                    WorksetTable _worksetTable = _linkdoc.GetWorksetTable();
                    IList<WorksetPreview> lstPreview = WorksharingUtils.GetUserWorksetInfo(_modelpath);

                    TaskDialog.Show("Revit","Start processing worksets in 1st preview");
                    foreach (WorksetPreview item in lstPreview)
                    {
                    	
                        Workset wkset = _worksetTable.GetWorkset(item.Id);
                        //if (!wkset.IsOpen)
                        if (wkset.IsOpen)
                        {
                        	TaskDialog.Show("Testing",wkset.Name.ToString());
                        	                
                            //if ((item.Name.CompareTo("Shared Levels and Grids") == 0) || (item.Name.CompareTo("Workset2") == 0) || (item.Name.CompareTo("Workset3") == 0))
                            if ((item.Name.ToString() == "Workset3") || (item.Name.ToString() == "Workset4"))
                            {
                            	TaskDialog.Show("Added Workset",wkset.Name.ToString());
                                lstWkSet_Close.Add(item.Id);
                                
                                continue;
                            }
                        }
                    }
                    String mycount = lstWkSet_Close.Count.ToString();
                    TaskDialog.Show("Ready to close this many worksets", mycount);
                    wk.Close(lstWkSet_Close);
                    _RvtLinkType.LoadFrom(_modelpath, wk);
                }

            }
            catch (Exception e)
            {
                TaskDialog.Show("dd", e.Message);
                return;
            }
            
            
            return;
Message 3 of 9
will.wydock
in reply to: stever66

Thank you for you help. I didn't get a chance to use your simplified if statement yet but I was able to figure out that I was missing workset configuration options.  I set it  to OpenLastViewed so that i could have it remember what was previously open/closed.

 

WorksetConfiguration wk = new WorksetConfiguration(WorksetConfigurationOption.OpenLastViewed);

As i was running the routine I found that running the wk.Close() would only close the ones that i asked it to close and would reopen others that I had previously closed. I had my worksetlist include the ones that were already closed and then add the ones that i needed  to also be closed.

 

WorksetConfiguration wk = new WorksetConfiguration(WorksetConfigurationOption.OpenLastViewed);
                    ModelPath _modelpath = _linkdoc.GetWorksharingCentralModelPath();
                    WorksetTable _worksetTable = _linkdoc.GetWorksetTable();
                    IList<WorksetPreview> lstPreview = WorksharingUtils.GetUserWorksetInfo(_modelpath);

                    foreach (WorksetPreview item in lstPreview)
                    {
                        Workset wkset = _worksetTable.GetWorkset(item.Id);
                        if (!wkset.IsOpen)
                        {
                            lstWkSet_Close.Add(item.Id);
                        }
                        else
                        {
                            if ((item.Name.CompareTo("Shared Levels and Grids") == 0) || (item.Name.CompareTo("1/4 SCOPEBOX AND MATCHLINE") == 0) || (item.Name.CompareTo("1/8 SCOPEBOX AND MATCHLINE") == 0))
                            {
                                lstWkSet_Close.Add(item.Id);
                                continue;
                            }
                        }
                    }
                    wk.Close(lstWkSet_Close);
                    _RvtLinkType.LoadFrom(_modelpath, wk);
Message 4 of 9
stever66
in reply to: will.wydock

Well that explains it.  Seems to make sense now.

 

Glad you figured it out. 

Message 5 of 9
MYS-JonathanT
in reply to: will.wydock

Hi @will.wydock ,

Is this working ? 

I am trying to do something similar  without success. 

The goal, I think is similar, close worksets from a number of linked revit models based on the workset name.

My workflow is as follows:

  1. Get all links (types not instances)
  2. for each linkType
  3. create workset configuaration
  4. create a list of workset
  5. get the workset (via FilteredWorksetCollector)
  6. if the workset name contains "Levels" add it's Id to the list of worksets
  7. if the list is not empty 
    1. close the worksets (WorksetConfiguration.Close(List of Id's)
    2. linktype.Reload()

It seems to be reloading the links but not closing the worksets , I get no errors 

Does it need to be wrapped in a Transaction ? I thought revit would complain about that. 

Any help/ ideas would be appriciated .

Thanks , Jonathan

 

 

Message 6 of 9

Running into the same problem - the code executes but the worksets are all left open. Did you ever find a solution?

Message 7 of 9

I figured it out - you need to construct the WorksetConfiguration like this to close worksets.

        workset_config = WorksetConfiguration(WorksetConfigurationOption.CloseAllWorksets)
        workset_config.Open(open_this_list_of_worksets)

I originally tried the code below, and it did not work - it left all the Worksets open. Seems like maybe a bug? That or the API just isn't clearly explaining how the WorksetConfiguration Class works...

        workset_config = WorksetConfiguration(WorksetConfigurationOption.OpenAllWorksets)
        workset_config.Close(close_this_list_of_worksets)

So to close Worksets, you need to create a list of the Worksets that you want to remain open.

 

Message 8 of 9

This vaguely matches the development team's assumption, which says:

   

I think you need to couple the workset unloading with a reload operation by using RevitLinkType.ReloadFrom( path, WorksetConfiguration ) that will let you specify the list of worksets which should be open after the load.

    

The similarity lies in the words 'specify the list of worksets which should be open'...

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 9 of 9

Sorry for resurrecting this thread a second time, but I have another topical issue. I have noticed that if you LoadFrom a Document that is loaded by two separate open models, the operation fails. For example, suppose I have three project files that link to each other - ARCH.rvt, MECH.rvt, ELEC.rvt. If I have the MECH and ELEC files open at the same time and try to perform a LoadFrom on the ARCH file, I receive this error:

 

Autodesk.Revit.Exceptions.InvalidOperationException: The link "this RevitLinkType" is loaded into multiple documents and cannot be reloaded.
 
However, I can modify the Worksets on the ARCH.rvt link through the Manage Worksets dialog box without any problems, so I'm thinking this LoadFrom operation is maybe not the correct solution?
Edit: Posting my code as well, if it helps.
 

 

'''
Goes to Manage > Manage Links > Manage Worksets and closes the three worksets for each LOADED link.

TESTED REVIT API: 2020

Author: Robert Perry Lackowski

'''
from pyrevit import DB
from Autodesk.Revit.DB import *

from pyrevit import script
output = script.get_output()

import traceback

doc = __revit__.ActiveUIDocument.Document
app = __revit__.ActiveUIDocument.Application.Application

# Decide if you want to hide it or unhide the worksets.
hide_workset = True
revit_link_types = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_RvtLinks).OfClass(DB.RevitLinkType).ToElements()
revit_link_instances = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_RvtLinks).OfClass(DB.RevitLinkInstance)
for link_type in revit_link_types:

    print "links? : " + link_type.LookupParameter("Type Name").AsString()
    
    if link_type.GetLinkedFileStatus() == LinkedFileStatus.Loaded:

        link_instance = list(filter(lambda x: (x.GetTypeId() == link_type.Id), revit_link_instances))[0]        
        link_document = link_instance.GetLinkDocument()
        
        #generate a list of the worksets in the link_document
        workset_table = link_document.GetWorksetTable()
        model_path = link_document.GetWorksharingCentralModelPath()
        lst_preview = WorksharingUtils.GetUserWorksetInfo(model_path)

        # initialize list of worksets to enable
        open_this_list_of_worksets = []
        
        for objWorksetPreview in lst_preview:
            wkset = workset_table.GetWorkset(objWorksetPreview.Id)
            
            if hide_workset:
                #gather a list of all the open worksets, EXCLUDING the worksets we want to hide
                if wkset.IsOpen and not (wkset.Name == "Shared Levels and Grids" or wkset.Name == 'Match Lines' or wkset.Name == 'Other Model Content'):
                    open_this_list_of_worksets.append(wkset.Id)
            else:
                #gather a list of all the open worksets, INCLUDING the ones we hid.
                if wkset.IsOpen or wkset.Name == "Shared Levels and Grids" or wkset.Name == 'Match Lines' or wkset.Name == 'Other Model Content':
                    open_this_list_of_worksets.append(wkset.Id)
        
        # Set the WorksetConfiguration file to close all worksets, then open the ones from the list
        workset_config = WorksetConfiguration(WorksetConfigurationOption.CloseAllWorksets)
        workset_config.Open(open_this_list_of_worksets)
        
        #reload the link with the updated workset configuration
        link_type.LoadFrom(model_path, workset_config) #FAILS WHEN LINK IS LINKED INTO TWO OPEN FILES. WORKS THROUGH UI THOUGH...
        
        #delete the workset configuration after use
        workset_config.Dispose()
print "Script complete."

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report