Viewport category

A schedule’s category is ScheduleGraphics but a legend’s category is Viewport the same as a regular view.

How can I differentiate between a legend and a view on a sheet when I’m selecting in the Revit window?
Eg, how do I prevent the user from selecting a regular view when all I want them to select is the legend view?

You can take a look here DynamoRevit/src/Libraries/RevitNodesUI/SelectionCombo.cs at 992ebc5512d218e7eea1305dad5e4e3519a5fcf3 · DynamoDS/DynamoRevit · GitHub at the Select Model Element by Category :slight_smile:

Are you asking how to get a legend view in Dynamo ?

hello there, you can use this Revit API and do a simple python script to achieve your task~

somewhere along the line of:

#Filter by the viewports in a sheet, follow by the ViewType of the view in the viewport
class sheetViewFilterByViewType(Autodesk.Revit.UI.Selection.ISelectionFilter):
	def __init__(self, viewSheet, viewType):
		self.ViewSheet = viewSheet
		self.ViewPortIds = list(viewSheet.GetAllViewports())
		self.ViewType = viewType
		
	def AllowElement(self, element):		
		if element.Id in self.ViewPortIds:
			actualViewId = element.ViewId
			actualView = element.Document.GetElement(actualViewId)
			return actualView.ViewType == self.ViewType
		return False
	
	def AllowReference(self, reference, position):
		return True

#Filter by ViewType.Legend only
class legendViewTypeFilter(Autodesk.Revit.UI.Selection.ISelectionFilter):
	def __init__(self): []
		
	def AllowElement(self, element):		
		if element.Category.Id == ElementId(BuiltInCategory.OST_Viewports):
			actualViewId = element.ViewId
			actualView = element.Document.GetElement(actualViewId)
			return actualView.ViewType == ViewType.Legend
		return False
	
	def AllowReference(self, reference, position):
		return True

selection = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument.Selection
objectType = Autodesk.Revit.UI.Selection.ObjectType.Element
promptMessage = "Whatever message you want it to be"
selectedReference = selection.PickObject(objectType , legendViewTypeFilter(), promptMessage)
selectedReference1 = selection.PickObject(objectType, sheetViewFilterByType(doc.ActiveView, Autodesk.Revit.DB.ViewType.Legend), promptMessage)
selectedViewPort = doc.GetElement(selectedReference)

Both filter should yield same result, but the first filter, in my opinion. will be more robust

2 Likes

Not exactly.

I’m asking how to allow the selection of ONLY a legend view.
The legend on a sheet is the same category as any other view. I’d like to specifically allow the user ONLY to select the legend.

That doesn’t show me how to get only legends unless I’m missing something?

There is no such thing as a legend on a sheet. A Viewport is placed on a sheet, so returning ‘viewport’ objects makes some sense.

So you’ll need to pre-filter (temporarily isolate in view) or post filter (remove if not a legend) to force the selection.

1 Like

So you’re saying what I want to do isn’t really possible?

It is, but I do not believe so using the method you have envisioned. The Revit API forum might have better insights though.

This is the issue. Viewports allows the selection of all viewports.
I’m trying to add @stillgotme’s suggestion but no luck so far.

I can’t get that to work.

The legend one keeps complaining about two arguments instead of one… But I can’t quite work out how to fix it. Any idea?

This is working for me. It will return the viewports on the sheet which contain a legend. You can ask a viewport for its view from there which has a node in later versions, or the ViewId property of the viewport itself if you prefer. As Jacob mentioned, legends occur as viewports on sheets, the legend itself is the single view in the browser.

# Made by Gavin Crump
# Free for use
# BIM Guru, www.bimguru.com.au

# Boilerplate text
import clr

import System
from System.Collections.Generic import List

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager 

clr.AddReference("RevitAPI")
clr.AddReference("RevitAPIUI")

import Autodesk 
from Autodesk.Revit.DB import *
from  Autodesk.Revit.UI import Selection
from  Autodesk.Revit.UI.Selection import ISelectionFilter

# Current doc/app/ui
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication 
uidoc = uiapp.ActiveUIDocument

# Force list function
def uwlist(input):
    result = input if isinstance(input, list) else [input]
    return UnwrapElement(result)

# Preparing input from dynamo to revit
runMe = IN[0]
elements = []

# Make selection filter class
class selectionfilter(ISelectionFilter):
	def AllowElement(self, element):
		try:
			vp_view = doc.GetElement(element.ViewId)
			if vp_view.ViewType == ViewType.Legend:
				return True
			else:
				return False
		except:
			return False

if runMe:
	# Create selection filter
	sel = uidoc.Selection.PickObjects(Selection.ObjectType.Element, selectionfilter())
	# Lists for appending/adding
	elementIds = List[ElementId]()
	# Try to get elements for selection
	for s in sel:
		try:
			id = s.ElementId
			el = doc.GetElement(id)
			elements.append(el)
			elementIds.Add(id)
		except:
			pass
	# Select the elements
	selection = uidoc.Selection.SetElementIds(elementIds)

# Preparing output to Dynamo
OUT = elements

Slight variants on processing the outcomes:

Just get the viewports and append to elements list:

if runMe:
	# Create selection filter
	sel = uidoc.Selection.PickObjects(Selection.ObjectType.Element, selectionfilter())
	# Lists for appending/adding
	elementIds = List[ElementId]()
	# Try to get elements for selection
	for s in sel:
		try:
			id = s.ElementId
			el = doc.GetElement(id)
			elements.append(el)
		except:
			pass

Get the legend of the viewport itself, append as elements:

if runMe:
	# Create selection filter
	sel = uidoc.Selection.PickObjects(Selection.ObjectType.Element, selectionfilter())
	# Lists for appending/adding
	elementIds = List[ElementId]()
	# Try to get elements for selection
	for s in sel:
		try:
			id = s.ElementId
			el = doc.GetElement(id)
			lv = doc.GetElement(el.ViewId)
			elements.append(lv)
		except:
			pass
4 Likes

Hello @Alien,
maybe can show me what error you are facing? a screenshot would be great!

but from the sound of it, it seems like you are missing some args from the def/constructor.

I get some of the same issues as before:

Hi,
ISelectionFilter and
Cpython, look at this message you have explanation

cordially
christian.stan

1 Like

Ahhh, that’s the reason I didn’t upgrade any of my original nodes.

I’ve just tried @GavinCrump’s code in Py2 and it’s much happier!

Thanks all :slight_smile:

3 Likes
  • sigh *

Someone is going to have to put some nodes together to pass these via zero touch nodes if we are going to make this scale. Not a fun task and it’s going to take a b it but I’m guessing it’ll go faster than waiting on Python to resolve it.

I will escalate to the Dynamo for Revit PM.

Isn’t it the .NET version that’s the issue rather than python itself?

All of the above.

Hi, personally, I’m patient, I’m still learning too much about python before trying to write Zero touch nodes in C#

cordially
christian.stan