Transfer unique view templates in Revit

, , ,
Import View Templates Revit

Transferring particular view templates from one Revit project to another can be troublesome from time to time. Put for example, when you tunned the last CD drawings set and you want to transfer an updated version of the modified view templates to another project. Duplicated view templates will add numerical prefixes and they have to be replaced manually.

All this without considering the possible changes that can happen afterward. The average case scenario is the one that view templates are updated more than once in the project lifecycle. Consequentially, new ones will be transferred and renamed while the outdated ones will have to be deleted.

The following script will avoid these headaches. This script is designed to import a specific view template from another project and to override the view template that has the same name in the host project. This means all the views will be updated with the new version of the view template.

# -*- coding: utf-8 -*-
"""Import View Templates.

NOTE: No schedule view template will be transferred. Same name view templates will be overriden and views will be updated.
"""
__title__ = 'Import View\nTemplates'
__author__ = "BIMicon"

# Import commom language runtime
import clr

# Import C# List
from System.Collections.Generic import List

# Import 
from pyrevit import revit, DB
from pyrevit import script
from pyrevit import forms

# Store current document into variable
doc = __revit__.ActiveUIDocument.Document
uidoc = __revit__.ActiveUIDocument

# Select opened documents to transfer View Templates
selProject = forms.select_open_docs(title="Select project/s to transfer View Templates", button_name='OK', width=500, multiple=True, filterfunc=None)

# Filter Views
viewsFilter = DB.ElementCategoryFilter(DB.BuiltInCategory.OST_Views)

# Function to retrieve View Templates
def retrieveVT(docList, currentDoc):
	storeDict = {}
	if isinstance(docList, list):
		for pro in docList:
			viewsCollector = DB.FilteredElementCollector(pro).WherePasses(viewsFilter)
			for view in viewsCollector:
				if view.IsTemplate == True:
					storeDict[view.Name + " - " + pro.Title] = view
	elif currentDoc == True:
		viewsCollector = DB.FilteredElementCollector(docList).WherePasses(viewsFilter)
		for view in viewsCollector:
			if view.IsTemplate == True:
				storeDict[view.Name] = view
	else:
		viewsCollector = DB.FilteredElementCollector(docList).WherePasses(viewsFilter)
		for view in viewsCollector:
			if view.IsTemplate == True:
				storeDict[view.Name + " - " + docList.Title] = view
	return storeDict

# Retrieve all view templates from selected docs
viewTemplates = retrieveVT(selProject, False)

# Display select view templates form
vTemplates = forms.SelectFromList.show(viewTemplates.keys(), "View Templates", 600, 300, multiselect=True)

# Collect all View Templates in the current document
docTemplates = retrieveVT(doc, True)

# Remove view templates with same name
vTemplatesNoProj = []
for vT in vTemplates:
	for p in selProject:
		if p.Title in vT:
			vTemplatesNoProj.append(vT.replace(p.Title, ""))

# Remove duplicated view templates from selection
newVTemplates = []
uniqueTemplates = []
for vNoProj, vT in zip(vTemplatesNoProj, vTemplates):
	if vNoProj not in uniqueTemplates:
		uniqueTemplates.append(vNoProj)
		newVTemplates.append(vT)

vTemplates = newVTemplates

# Collect all views from the current document
docViewsCollector = DB.FilteredElementCollector(doc).WherePasses(viewsFilter)

# Check for duplicate View Templates in the current project
dupViewTemplates = []
for vN, vT in docTemplates.items():
	for v in vTemplates:
		if vN in v:
			dupViewTemplates.append(vT)

# Views with view templates
def checkViewT(viewsList):
	viewsWVT = {}
	for v in viewsList:
		if v.ViewTemplateId != DB.ElementId.InvalidElementId:
			viewsWVT.setdefault(v.ViewTemplateId.ToString(), []).append(v)
	return viewsWVT

# Transform object
transIdent = DB.Transform.Identity
copyPasteOpt = DB.CopyPasteOptions()

# Create single transaction and start it
t = DB.Transaction(doc, "Copy View Templates")
t.Start()

# Check for all views that has a view template
vTIds = []
viewsWVT = checkViewT(docViewsCollector)
viewsFail = []
viewsSuccess = []
for vT in vTemplates:
	vTId = List[DB.ElementId]()
	for pro in selProject:
		if pro.Title in vT:
			vTId.Add(viewTemplates[vT].Id)
			# Check if view template is used in current doc
			if vT.replace(" - " + pro.Title, "") not in docTemplates.keys():
				# If not, copy the selected View Template to current project
				DB.ElementTransformUtils.CopyElements(pro, vTId, doc, transIdent, copyPasteOpt)
			# View templates are already in use in the current project
			else:
				vToApplyVT = []
				# Loop through each view template in use in the current document
				for k in viewsWVT.keys():
					views = viewsWVT[k]
					# Helper variable to mark the first time to run the script
					flag = True
					# Assign new view template to each view
					for v in views:
						# Retrieve view template for first time use
						if flag:
							elName = doc.GetElement(v.ViewTemplateId).Name
							if elName in vT:
								doc.Delete(v.ViewTemplateId)
								et = DB.ElementTransformUtils.CopyElements(pro, vTId, doc, transIdent, copyPasteOpt)
							else:
								break
						# Assign view template
						try:
							v.ViewTemplateId = et[0]
							viewsSuccess.append(v.Name)
							flag = False
						except:
							viewsFail.append(v.Name)
							flag = False

# Commit transaction
t.Commit()

# Function to display result to user
def printMessage(resultList, failedList, message, messageWarning):
	if len(resultList) != 0:
		print(message)
		print("\n".join(resultList))
	if len(failedList) != 0:
		print(messageWarning)
		print("\n".join(resultList))

# Print message
printMessage(viewsSuccess, viewsFail, "The following view templates have been changed:",
			"View templates failed to apply to views, make sure the proper view template type is named:")

A few comments about the code:

The script doesn’t deal with schedule view templates, as every schedule view is collected by the class ViewSchedule. This is an idea that can be developed easily and suggestions can be found at the end of this post.

Lines 1-22: usual boilerplate code. Something worth to highlight is line 18, where instead of importing Win Forms, we imported a module in pyRevit that allows us to use forms without creating them from .NET ourselves.

Lines 24-97: all auxiliary code and operations that make the program work:

  • Retrieves all opened documents except the active one.
  • Call form to allow the user to select desired projects.
  • Retrieve all view templates from the previous documents.
  • Call form to allow the user to select desired view templates.
  • Retrieve all view templates from the current document.
  • Check for view templates that have the same name as in the projects to import.
  • Function to collect all views with view templates.

Lines 99-145: the main function to transfer view templates. Basically, it splits the view templates between the ones with the same name as a view template in the project and those that aren’t present in the host project. In the latest case, it directly imports them. In the first case, it will delete the view template first, import the external view template and apply this one to all the views that were assigned with the old view template.

As output, it stores a list of views that have been successfully updated.

Lines 147-158: Display to the user which views have been successfully updated with the new view templates.

This is the script, in a nutshell, it works and it is quite easy to implement, saving us from big headaches like having to delete more than 30 alien view templates imported throughout several different projects.

Icon and script can be downloaded from here:

DEVELOPMENT IDEA:

An option to retrieve and import schedule view templates is to collect all schedule views and check if they are view templates. After that, we can add a for loop to check for schedule view templates inside the retrieveVT. It will be a fun exercise!

Leave a Reply

Your email address will not be published. Required fields are marked *