Transfer View Templates

Let's continue where we stopped at the previous lesson and learn how to transfer View Templates between projects

Transfer View Templates

Let's continue where we stopped at the previous lesson and learn how to transfer View Templates between projects

Download Files

Summary

Intro

We will continue this lesson with the code from the previous one. The lesson was getting too long, so I split it into 2 parts.

In this second part, you will learn how to transfer View Templates between projects, and most importantly, how to override its parameters.

Why Transfer ViewTemplates

I know that many people work on projects with multiple buildings, and we often split them into separate models. This workflow has a ton of benefits, but also means that we have to be smarter managing our standards, families and other things across projects.

Including - ViewTemplates.

So I wanted to show you how to transfer them and also show you the nuances about overriding its parameters.

Get Projects

Firstly, we need to get 2 projects.

You've seen that in the video, I've used 2 simple projects, and I made sure that I removed all the View Templates in one of them, so it's easy to see when we bring new ones in.

You might want to create some form to ask user Project_from and Project_to, but I kept it simple for the lesson and got all my projects with app.Documents.

💡Keep in mind that you will get DocumentSet, and you can't get items by using indexes. Therefore, make sure you convert it into python list()

# ➡️ TRANSFER VIEW TEMPLATES ACROSS PROJECTS

#📦 Get Documents
app = __revit__.Application
all_docs = list(app.Documents)
doc_from = all_docs[0] # Adjust selection to your needs!
doc_to   = all_docs[1] # Adjust selection to your needs!

print('Copy ViewTemplates:')
print('-'*50)
print('Copying from: {}'.format(doc_from.Title))
print('Copying To: {}'.format(doc_to.Title))

⚠️ From now on, pay attention to which doc you use.

It's important when you want to get the right elements, create transaction and other steps that might involve doc variable.

It's very common to use the default doc variable instead of specific doc_to/doc_from and it can cause some errors. But I've showed you a few cases where it might occur.

Select ViewTemplates

Once you have your projects, we can get all ViewTemplates and ask user to select which ones to copy. For that we will use Dictionary and sort data like {VT.Name : VT}

Once we have a dictionary of ViewTemplates, we can use pyrevit.forms.SelectFromList to ask user to select from the list. Also make sure you set multiselect=True.

Then after user will make the selection, you can create list of selected ViewTemplates and list of their Ids.


#👉 SELECT View Templates to Transfer
from pyrevit.forms import SelectFromList

all_views = FilteredElementCollector(doc_from).OfCategory(BuiltInCategory.OST_Views).ToElements()
all_vt    = [v for v in all_views if v.IsTemplate]
dict_vt   = {vt.Name:vt for vt in all_vt}

sel_vt_names = SelectFromList.show(dict_vt.keys(), button_name='Select ViewTemplate', multiselect=True)
sel_vt       = [dict_vt[vt_name] for vt_name in sel_vt_names]
sel_vt_ids   = [vt.Id for vt in sel_vt]
Copy ViewTemplates

Now we have everything we need, so we can Copy our ViewTemplates.

For that we will use ElementTransformUtils.CopyElements, which needs:

Overall, it's simple to use because we will create default options for the Transform and CopyPasterOptions, so we just need

  • doc_from

  • doc_to

  • list_of_el_ids

Here is the code snippet of how it works:


#🔓 Start Transaction
t = Transaction(doc_to, 'Copy ViewTemplates')
t.Start() #🔓

List_copy_el_ids = List[ElementId](sel_vt_ids)
transform = Transform.Identity
options   = CopyPasteOptions()

ElementTransformUtils.CopyElements(doc_from,
                                     List_copy_el_ids,
                                     doc_to,
                                     transform,
                                     options)


t.Commit() #🔒
print('✔️ ViewTemplate Transfer is Completed!')

💡 Make sure you use correct doc in the Transaction.

You might get an error if you use regular doc, which will be the Active Document. This is a common mistake we do because of a habit. And it might even work if you have the right project open. So pay attention here.

Example 1 - Complete Snippet:

Here is the snippet put together

#⬇️ Imports
from Autodesk.Revit.DB import *
import clr
clr.AddReference('System')
from System.Collections.Generic import List


#📦 VARIABLES
#==================================================
app    = __revit__.Application
uidoc  = __revit__.ActiveUIDocument
doc    = __revit__.ActiveUIDocument.Document #type:Document

# ➡️ TRANSFER VIEW TEMPLATES ACROSS PROJECTS

#📦 Get Documents
app = __revit__.Application
all_docs = list(app.Documents)
doc_from = all_docs[0] # Adjust selection to your needs!
doc_to   = all_docs[1] # Adjust selection to your needs!

print('Copy ViewTemplates:')
print('-'*50)
print('Copying from: {}'.format(doc_from.Title))
print('Copying To: {}'.format(doc_to.Title))


#👉 SELECT View Templates to Transfer
from pyrevit.forms import SelectFromList

all_views = FilteredElementCollector(doc_from).OfCategory(BuiltInCategory.OST_Views).ToElements()
all_vt    = [v for v in all_views if v.IsTemplate]
dict_vt   = {vt.Name:vt for vt in all_vt}

sel_vt_names = SelectFromList.show(dict_vt.keys(), button_name='Select ViewTemplate', multiselect=True)
sel_vt       = [dict_vt[vt_name] for vt_name in sel_vt_names]
sel_vt_ids   = [vt.Id for vt in sel_vt]

#🔓 Start Transaction
t = Transaction(doc_to, 'Copy ViewTemplates')
t.Start() #🔓

List_copy_el_ids = List[ElementId](sel_vt_ids)
transform = Transform.Identity
options   = CopyPasteOptions()

ElementTransformUtils.CopyElements(doc_from,
                                     List_copy_el_ids,
                                     doc_to,
                                     transform,
                                     options)


t.Commit() #🔒
print('✔️ ViewTemplate Transfer is Completed!')
Transfer and Override ViewTemplate

You might notice that if you try to copy the ViewTemplate that already exists, it doesn't change it. But instead, it will create a copy of that ViewTemplate.

It might be a good idea sometimes, but mostly, we want to transfer and update ViewTemplates with the same name. So let's look into how we're going to do that.

Brainstorming

We will have to do the following steps:

  • Get A/B Documents

  • Ask user to select ViewTemplates from doc_A

  • 1. Find matching ViewTemplate in doc_B and sort views that use it

  • 1.2 Delete matching ViewTemplates

  • 2. Copy ViewTemplates (they will be new, because we deleted matching one)

  • 3. Reassign ViewTemplates to Views which used these templates.

By doing these steps, we've first cleared any duplicates and brough viewTemplates as new. And then we made sure that all the views have exactly the same ViewTemplates, as before we deleted them.

So Firstly, let's prepare our main part in the code. Also, I will use my ef_Transaction, which me made in the context-manager lesson, so we can save some space here.

from Snippets._context_managers import ef_Transaction

#1️⃣ Delete Matching ViewTemplates
with ef_Transaction(doc_to, 'Delete ViewTemplates', debug = True):
    dict_del_vt = delete_existing_view_templates(doc_to, sel_vt_names)


#2️⃣  COPY ELEMENTS
with ef_Transaction(doc_to, 'Copy ViewTemplates', debug = True):
    List_copy_el_ids = List[ElementId](sel_vt_ids)
    transform = Transform.Identity
    options   = CopyPasteOptions()
    ElementTransformUtils.CopyElements(doc_from, List_copy_el_ids, doc_to, transform, options)


#3️⃣ Reassign ViewTemplates
with ef_Transaction(doc_to, 'Delete ViewTemplates', debug = True):
    reassign_del_view_templates(doc_to, dict_del_vt)


print('✔️ ViewTemplate Transfer is Completed!')

Now we need to write functions for:

  1. Delete matching ViewTemplates

  2. Reassign ViewTemplates

Delete matching ViewTemplates

Before we are going to delete existing ViewTemplates, we need to collect all the views that use them.

So we will create a dictionary, and then iterate through all the views in doc_to.

Then we will check if the view has a ViewTemplate, and if its name is in the list of ViewTempalte Names that we want to Transfer. If we have a match we will write it in a dictionary.

Once we created a sorted dictionary of views sorted by matching ViewTemplates, we can iterate and start deleting these ViewTemplates.

Lastly, don't forget to return your dictionary of sorted views, we will need it to reassign ViewTemplates.

Here is the complete function to do all that:

#➡️ TRANSFER VIEW TEMPLATES ACROSS PROJECTS
# 🧬 FUNCTIONS

def delete_existing_view_templates(given_doc, list_vt_names):
    """This function will delete ViewTemplates in the given doc based on list of provided ViewTemplate Names.
        The Dictionary will be returned of removed ViewTemplates and all the views where it was used.
        e.g. {ViewTemplate.Name : list(View1,View2)}"""

    # 📦 Create Container
    from collections import defaultdict
    dict_del_vt = defaultdict(list)  # {VT.NAME: [LIST OF VIEWS WHERE IT USED]}

    # 👉 Get Views and ViewTemplates
    all_views_vt = FilteredElementCollector(given_doc).OfCategory(BuiltInCategory.OST_Views).ToElements()
    all_views = [v for v in all_views_vt if not v.IsTemplate]
    all_vt = [v for v in all_views_vt if v.IsTemplate]

    # 🔬 Sort Views by ViewTemplates
    for view in all_views:
        vt_id = view.ViewTemplateId

        # View has ViewTempate
        if vt_id != ElementId(-1):
            vt = doc.GetElement(vt_id)
            if vt.Name in list_vt_names:
                dict_del_vt[vt.Name].append(view)

    # 🔥 Delete Matching ViewTemplates
    for vt in all_vt:
        if vt.Name in list_vt_names:
            doc_to.Delete(vt.Id)

    return dict_del_vt

Once this step is complete we will Copy Elements same as we did before.

Reassign ViewTemplates

We've deleted matching ViewTemplates, transfered the desired ones. So, it's time to assign ViewTemplates back to the same views.

It's very simple, because we already have a dictionary that has all the views and the name of the ViewTemplate.

So we need to get all ViewTemplates in the project, and then iterate through to get the ones that we need by checking if their name is in the dictionary.

Then we will iterate through views, and assign ViewTemplate with the same name as before.

def reassign_del_view_templates(given_doc, dict_vt):
    #👉 Get All ViewTemplates
    all_vt = [v for v in FilteredElementCollector(given_doc).OfClass(View).ToElements() if v.IsTemplate]

    for vt_name, list_views in dict_vt.items():
        #🔎 FIND VIEWTEMPLATE WITH SAME NAME
        new_vt = [v for v in all_vt if v.Name == vt_name][0] # ONLY IF YOU 100% ALL VT_NAMES ARE IN THE PROJECT

        #✅ SET VIEWTEMPLATE TO VIEWS
        for view in list_views:
            view.ViewTemplateId = new_vt.Id
Final Code Snippet

Here is the complete snippet to Transfer ViewTemplates and override their parameters.

#⬇️ Imports
from Autodesk.Revit.DB import *
import clr
clr.AddReference('System')
from System.Collections.Generic import List


#📦 VARIABLES
#==================================================
app    = __revit__.Application
uidoc  = __revit__.ActiveUIDocument
doc    = __revit__.ActiveUIDocument.Document #type:Document


# ➡️ TRANSFER VIEW TEMPLATES ACROSS PROJECTS
# 🧬 FUNCTIONS

def delete_existing_view_templates(given_doc, list_vt_names):
    """This function will delete ViewTemplates in the given doc based on list of provided ViewTemplate Names.
        The Dictionary will be returned of removed ViewTemplates and all the views where it was used.
        e.g. {ViewTemplate.Name : list(View1,View2)}"""

    # 📦 Create Container
    from collections import defaultdict
    dict_del_vt = defaultdict(list)  # {VT.NAME: [LIST OF VIEWS WHERE IT USED]}

    # 👉 Get Views and ViewTemplates
    all_views_vt = FilteredElementCollector(given_doc).OfCategory(BuiltInCategory.OST_Views).ToElements()
    all_views = [v for v in all_views_vt if not v.IsTemplate]
    all_vt = [v for v in all_views_vt if v.IsTemplate]

    # 🔬 Sort Views by ViewTemplates
    for view in all_views:
        vt_id = view.ViewTemplateId

        # View has ViewTempate
        if vt_id != ElementId(-1):
            vt = doc.GetElement(vt_id)
            if vt.Name in list_vt_names:
                dict_del_vt[vt.Name].append(view)

    # 🔥 Delete Matching ViewTemplates
    for vt in all_vt:
        if vt.Name in list_vt_names:
            doc_to.Delete(vt.Id)

    return dict_del_vt


def reassign_del_view_templates(given_doc, dict_vt):
    #👉 Get All ViewTemplates
    all_vt = [v for v in FilteredElementCollector(given_doc).OfClass(View).ToElements() if v.IsTemplate]

    for vt_name, list_views in dict_vt.items():
        #🔎 FIND VIEWTEMPLATE WITH SAME NAME
        new_vt = [v for v in all_vt if v.Name == vt_name][0] # ONLY IF YOU 100% ALL VT_NAMES ARE IN THE PROJECT

        #✅ SET VIEWTEMPLATE TO VIEWS
        for view in list_views:
            view.ViewTemplateId = new_vt.Id



#📦 Get Documents
app = __revit__.Application
all_docs = list(app.Documents)
doc_from = all_docs[0] # Adjust selection to your needs!
doc_to   = all_docs[1] # Adjust selection to your needs!

print('Copy ViewTemplates:')
print('-'*50)
print('Copying from: {}'.format(doc_from.Title))
print('Copying To: {}'.format(doc_to.Title))


#👉 SELECT View Templates to Transfer
from pyrevit.forms import SelectFromList

all_views = FilteredElementCollector(doc_from).OfCategory(BuiltInCategory.OST_Views).ToElements()
all_vt    = [v for v in all_views if v.IsTemplate]
dict_vt   = {vt.Name:vt for vt in all_vt}

sel_vt_names = SelectFromList.show(dict_vt.keys(), button_name='Select ViewTemplate', multiselect=True)
sel_vt       = [dict_vt[vt_name] for vt_name in sel_vt_names]
sel_vt_ids   = [vt.Id for vt in sel_vt]



from Snippets._context_managers import ef_Transaction

#1️⃣ Delete Matching ViewTemplates
with ef_Transaction(doc_to, 'Delete ViewTemplates', debug = True):
    dict_del_vt = delete_existing_view_templates(doc_to, sel_vt_names)


#2️⃣  COPY ELEMENTS
with ef_Transaction(doc_to, 'Copy ViewTemplates', debug = True):
    List_copy_el_ids = List[ElementId](sel_vt_ids)
    transform = Transform.Identity
    options   = CopyPasteOptions()
    ElementTransformUtils.CopyElements(doc_from, List_copy_el_ids, doc_to, transform, options)


#3️⃣ Reassign ViewTemplates
with ef_Transaction(doc_to, 'Delete ViewTemplates', debug = True):
    reassign_del_view_templates(doc_to, dict_del_vt)


print('✔️ ViewTemplate Transfer is Completed!')

Discuss the lesson:

P.S. Sometimes this chat might experience connection issues.
Please be patient or join via Discord app so you can get the most out of this community and get access to even more chats.

P.S. Sometimes this chat might experience connection issues.
Please be patient or join via Discord app so you can get the most out of this community and get access to even more chats.

© 2023-2024 EF Learn Revit API

© 2023-2024 EF Learn Revit API

© 2023-2024 EF Learn Revit API