Close and open worksets using dynamo/python

I am new to Dynamo.
I have a model contain many revit links and each link in a individual workset.
Is there any way to open or close certain worksets?

HI @raysonchan0305, Welcome to Dynamo and the Dynamo Forum! :slight_smile:

There is no way with the OOTB Dynamo nodes that I’m aware of (although, there are most likely packages out there with these features). However, this can be done via the API relatively easily. I have created a graph for this that uses python and the Revit API to reload the chosen link with worksets chosen by the user…

Here is a quick demo…

And the Dynamo Script…
ReloadLinksWithSelectedWorksets.dyn (46.4 KB)

NOTE: Please make sure you read the comments in the graph as you will need to change some of the logic to suit your needs (which revit link you are reloading and which worksets you want to open). Hopefully my explanations are clear enough.

Suggested Improvements: As a rule, I don’t put any third party nodes in any of my graphs that I put on the forum, but a suggestion to make this more complete would be to put DataShapes UI nodes in there so user can run and Select the Revit Link and Worksets via a User Interface (rather than editing the graph directly).

Hope you find this useful and at a later date when you are more confident you can get to grips with the python.

Cheers,
Dan

4 Likes

Hello
just for the challenge and fun :slight_smile:
an example with Winform

import clr
import sys
#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *

#import net library
clr.AddReference('System')
from System.Collections.Generic import List

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

#Get Important vars
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application

clr.AddReference('System.Drawing')
clr.AddReference('System.Windows.Forms')
import System.Drawing
import System.Windows.Forms

from System.Drawing import *
from System.Windows.Forms import *

class WksetLnkUtils(Form):
    def __init__(self):
        rvtLinkInst = FilteredElementCollector(doc).OfClass(RevitLinkInstance)
        self._dictRvtInstance = {}
        for x in rvtLinkInst:
            _lkdoc = x.GetLinkDocument()
            if _lkdoc.IsWorkshared:
                self._dictRvtInstance[x.Name] = x
        self._dictWkset = {}
        self.rvtRvtlinkType = None
        self.out = None
        self.InitializeComponent()
    
    def InitializeComponent(self):
        self._groupBox1 = System.Windows.Forms.GroupBox()
        self._checkedListBox1 = System.Windows.Forms.CheckedListBox()
        self._buttonOpen = System.Windows.Forms.Button()
        self._buttonClose = System.Windows.Forms.Button()
        self._comboBoxRvtLink = System.Windows.Forms.ComboBox()
        self._groupBox2 = System.Windows.Forms.GroupBox()
        self._groupBox1.SuspendLayout()
        self._groupBox2.SuspendLayout()
        self.SuspendLayout()
        # 
        # groupBox1
        self._groupBox1.Controls.Add(self._checkedListBox1)
        self._groupBox1.Location = System.Drawing.Point(30, 123)
        self._groupBox1.Name = "groupBox1"
        self._groupBox1.Size = System.Drawing.Size(361, 423)
        self._groupBox1.TabIndex = 0
        self._groupBox1.TabStop = False
        self._groupBox1.Text = "Select Workset"
        # 
        # checkedListBox1
        self._checkedListBox1.FormattingEnabled = True
        self._checkedListBox1.Items.Clear()
        self._checkedListBox1.Location = System.Drawing.Point(16, 42)
        self._checkedListBox1.Name = "checkedListBox1"
        self._checkedListBox1.Size = System.Drawing.Size(326, 361)
        self._checkedListBox1.TabIndex = 0
        # 
        # buttonOpen
        self._buttonOpen.Location = System.Drawing.Point(60, 560)
        self._buttonOpen.Name = "buttonOpen"
        self._buttonOpen.Size = System.Drawing.Size(300, 40)
        self._buttonOpen.TabIndex = 1
        if app.Language == Autodesk.Revit.ApplicationServices.LanguageType.French:
            self._buttonOpen.Text = "Ouvrir les sous-projets selectionnés \n(les autres seront fermés)"
        else:
            self._buttonOpen.Text = "Open Selected Worksets (others will be close)"     
        self._buttonOpen.UseVisualStyleBackColor = True
        self._buttonOpen.Click += self.ButtonOpenClick
        # 
        # buttonClose
        self._buttonClose.Location = System.Drawing.Point(60, 620)
        self._buttonClose.Name = "buttonClose"
        self._buttonClose.Size = System.Drawing.Size(300, 40)
        self._buttonClose.TabIndex = 1
        if app.Language == Autodesk.Revit.ApplicationServices.LanguageType.French:
            self._buttonClose.Text = "Fermer les sous-projets selectionnés \n(les autres seront ouverts)"
        else:
            self._buttonClose.Text = "Close Selected Worksets (others will be open)"
        self._buttonClose.UseVisualStyleBackColor = True
        self._buttonClose.Click += self.ButtonCloseClick
        # 
        # comboBoxRvtLink
        self._comboBoxRvtLink.Items.AddRange(System.Array[System.Object](self._dictRvtInstance.keys()))
        self._comboBoxRvtLink.FormattingEnabled = True
        self._comboBoxRvtLink.Location = System.Drawing.Point(19, 41)
        self._comboBoxRvtLink.Name = "comboBoxRvtLink"
        self._comboBoxRvtLink.Size = System.Drawing.Size(323, 24)
        self._comboBoxRvtLink.TabIndex = 2
        self._comboBoxRvtLink.SelectedIndexChanged += self.ComboBoxRvtLinkSelectedIndexChanged
        # 
        # groupBox2
        self._groupBox2.Controls.Add(self._comboBoxRvtLink)
        self._groupBox2.Location = System.Drawing.Point(30, 17)
        self._groupBox2.Name = "groupBox2"
        self._groupBox2.Size = System.Drawing.Size(361, 89)
        self._groupBox2.TabIndex = 3
        self._groupBox2.TabStop = False
        self._groupBox2.Text = "Select Revit Link"
        # 
        # MainForm
        self.ClientSize = System.Drawing.Size(430, 700)
        self.Controls.Add(self._groupBox2)
        self.Controls.Add(self._buttonClose)
        self.Controls.Add(self._buttonOpen)
        self.Controls.Add(self._groupBox1)
        self.Name = "WksetLnkUtils"
        self.Text = "Manage linked model Worksets"
        self._groupBox1.ResumeLayout(False)
        self._groupBox2.ResumeLayout(False)
        self.ResumeLayout(False)


    def setLinkstatut(self, wksetsId):
        if self.rvtRvtlinkType is not None:
            #create WorksetConfiguration with CloseAllWorksets by default
            wkstConfig = WorksetConfiguration(WorksetConfigurationOption.CloseAllWorksets)
            lstWksetId = List[WorksetId](wksetsId)
            wkstConfig.Open(lstWksetId) 
            loada = self.rvtRvtlinkType.LoadFrom(self.mpath, wkstConfig)
            self.out = loada.LoadResult
            wkstConfig.Dispose()        
            
    def ButtonOpenClick(self, sender, e):
        wksetsId = [ self._dictWkset.get(wksetnam) for wksetnam in self._checkedListBox1.CheckedItems]
        self.setLinkstatut(wksetsId)


    def ButtonCloseClick(self, sender, e):
        self.wksetsId = []
        #get items are not checked for open others Worksets
        setDiff = set(self._checkedListBox1.Items) - set(self._checkedListBox1.CheckedItems)
        wksetsId = [ self._dictWkset.get(wksetnam) for wksetnam in setDiff]
        self.setLinkstatut(wksetsId)


    def ComboBoxRvtLinkSelectedIndexChanged(self, sender, e):
        rvtLinkInstance = self._dictRvtInstance.get(sender.Text)
        self.rvtRvtlinkType = doc.GetElement(rvtLinkInstance.GetTypeId())
        _linkdoc = rvtLinkInstance.GetLinkDocument()
        _worksetTable = _linkdoc.GetWorksetTable()
        self.mpath = _linkdoc.GetWorksharingCentralModelPath()
        
        lstPreview =  WorksharingUtils.GetUserWorksetInfo(self.mpath)
        self._dictWkset = {item.Name : _worksetTable.GetWorkset(item.Id).Id for item in lstPreview }
        self._checkedListBox1.Items.Clear()
        self._checkedListBox1.Items.AddRange(System.Array[System.Object](self._dictWkset.keys()))
        
objForm = WksetLnkUtils()
objForm.Show()

OUT = 0

the interface can be further improved with a TreeNode with checkbox

10 Likes

Very nice! I am way too lazy! :grinning:

1 Like

Hi Daniel,

Wonderful, this is exactly what I want.
Thanks for your help!
I still learning both dynamo and python.

cool!

You’re welcome Rayson! Happy to help! :blush:

Hi All,

I was wondering if anyone knows how to close or open worksets in the given document (current)?
I am not good with Python (started to learn, or more like beginning to learn) any any help would be appreciated.
I know I can do it manually but I need this as a part of a bigger script :). I assume this python script could be simplified to achieve what i need.

Hi @Karolina.Lisiecka,

In the graph I uploaded earlier, the python it is broken down into smaller chucks as nodes. You might find these suit your requirements a little better.

Hi @Daniel_Woodcock1,

Thank you for such a prompt reply.
I will give it a go and try to adjust the script once I have some time.
Will let you know if I can make it work :slight_smile:

1 Like

Hello Daniel,

I tried to Run the script but get this warning.
Any idea how to solve this one?

1 Like

Hi @c.poupin impressive work! what are the modifications to make to your script so that it works with the models hosted on the cloud (BIM360)?

1 Like

Hello @Dave_O
I don’t know for this, currently I don’t have BIM 360 for testing