Get Currently-selected Excel Cells (for subsequent Revit Action)

I have a long list of excel elements (element IDs) in excel. Every so often, I want to select a subset of the list, and have the Revit 3D view readjust by selecting the elements and radjusting the scope box.
To achieve this in Dynamo, I believe I need to put together a graph that reads the currently-selected Excel cells, forms a list or string that can be input to a Revit node that selects by elementIDs.
I’m trying to find those two key nodes that interface with Excel, and Revit… No luck thus far. Can anyone point me to the correct packages?

I have indeed looked myself – but Excel packages seem to read from Excel files, and not the open instance of Excel. Then there’s a package called Modellical that seems to have a SelectInRevit node, but I think I need Dynamo 2.0.2 for that, whereas I have a Revit 2018 model (Dynamo 2.0.2 doesn’t play well with 2018 I hear?)

Dynamo 2.0.2 does play well with 2018, but 2.0.3 plays even better and is worth the update.

1 Like

cheers, I took a chance and installed it. Now I have the bumblebee package and another package called “Elementids Excel List to Revit Elements”. This second package is just one node that takes an Excel sheet and range as input, then selects the elements in Revit. I need to modify that node, and I’ve determined that the bumblebee package can Live Read my open Excel package, and output a list; so I want to transplant that bumblebee ouput into the latter half of the “Elementids Excel List…” node. See the graph I have so far.

The trouble is tha tI don’t want to manually define the range – I want to live-read the cells I have selected in Excel.

hello
a solution using COM Interface Interop.Excel

import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

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

clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *
from Autodesk.Revit.UI.Selection import *


clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument

import System
from System.Collections.Generic import List
clr.AddReferenceByName('Microsoft.Office.Interop.Excel, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c' )
from Microsoft.Office.Interop import Excel
from System.Runtime.InteropServices import Marshal

refreshBoolean = IN[0]

def checkInteger(val):
    try:
        check = int(val)
        return True
    except: return False 
    
class OpenFileException(Exception):
    pass

class Lst_Xls():
    def __init__(self):
        try:   
            ex = System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application")
        except: 
            ex = Excel.ApplicationClass()   
        ex.Visible = True
        self.app = ex 
        self.error = None
        self.data = []  
        self.workbook = ex.ActiveWorkbook
        ws = ex.ActiveSheet
        selectRange = ex.Selection   
        for r in selectRange:
            self.data.append(r.Value2)
            
    def closeProperly(self):
        if self.workbook is not None:
            Marshal.ReleaseComObject(self.workbook)
        if self.app is not None:
            Marshal.ReleaseComObject(self.app)     
        self.workbook = None        
        self.app = None
            
        
objxls = Lst_Xls()  
if objxls.error is None:
    iLstId = List[ElementId]()
    outElem = []
    for val in objxls.data:
        if checkInteger(val):
            elemId = ElementId(int(val))
            elem = doc.GetElement(elemId)
            if elem is not None:
                outElem.append(elem)
                iLstId.Add(elem.Id)
    uidoc.Selection.SetElementIds(iLstId)           
    OUT = outElem
    
else: 
    OUT = "Error "
objxls.closeProperly()  
7 Likes

I’ll be trying this out in the next few days, and will let you know. It looks promising. As an infrequent Dynamo user, I tried implementing it once already and should warn that having Dynamo on Auto-run, and defining that Python node, will just freeze Dynamo :stuck_out_tongue: Need to get my model open and Dynamo back on again, with the boolean operator in first.

I’ve replciated your exat graph, but can’t get any reaction from the Phython Script node. even if I change the code to include OUT = “testing” as line 1 of the code, the Watch node is blank. I flip the switch from True/False, and Automatic to Manual several times. Excel and Revit 2018 are open (but this shouldn’t matter for the “testing” code).

@mike.kovacs
the script does not find an instance of Excel…
make sure all Excel process are closed before open Excel file and launch script


I update the code

1 Like

Brilliant! That was helpful for getting your code to run. I’m much further along now.

I can select element IDs in Excel and get an adjustable section box around them (see the graph below). However, the elements aren’t actually being “selected” – i.e. they’re not highlighted in Revit. So I found some code that would do that (Select Revit Elements by ID in Dynamo) but it’s throwing a Warning I can’t quite resolve.

Warning: IronPythonEvaluator.EvaluateIronPythonScript operation failed.
Traceback (most recent call last):
File “”, line 26, in
TypeError: Unable to cast object of type ‘Revit.Elements.Floor’ to type
‘Autodesk.Revit.DB.ElementId’.

The code for the select revit element by ID node

import clr
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import ElementId
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
clr.AddReference("System")
from System.Collections.Generic import List

uiapp = DocumentManager.Instance.CurrentUIApplication

ids = IN[0]

# if it's not a list, make it a list
if not isinstance(ids, list):
	ids = [ids]

# convert to element ids
elemIds = []
for id in ids:
    elemIds.append(ElementId(id))
    

# cast to icollection and select
uiapp.ActiveUIDocument.Selection.SetElementIds(List[ElementId](elemIds));

#Assign your output to the OUT variable.
OUT = 0

@mike.kovacs

I update the code with selection

you can also use the Periodic Mode

5 Likes

Brilliant! Thanks very much for your support in achieving this

Hi,
I am very interested in using this solution. Thank you so much.

I’ve tried the code, but I’m getting an error. Please see below.
When I run the script, a new excel empty window opens, and then I get the error message below.
Thanks in advance

Hello @a.halim
make sure all Excel process are closed before open Excel file and launch script


Which Excel version are you using?

Thank you @c.poupin for your reply , I made sure to close all the Excel files and I still have the same issue.
I use this Microsoft package
Do you think it could be because of a language compatibility ?
My Revit is French (2021) and Microsoft Office 2019 is in English.
image

@a.halim
try to replace this line
ex = System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application")
by this
ex = System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application.16")

and check if any instance of Excel is running in the background