Ryan Lenihan

BIM360 Docs – How to Download RVT instead of ZIP

Have you ever noticed that sometimes when you download model source files from BIM360, sometimes they’re a singular Revit model and sometimes they’re a bundled ZIP package containing the Revit links?

Ever wondered why, or how to change this to get just the singular model?

They’re generally pretty easy to spot in the BIM360 web portal, you just need to look at the file size.

The files highlighted in green which have a much smaller file size will be downloaded as the singular Revit file, while the files highlighted in red with the larger file size will pull down the file plus it’s links in a ZIP package.

The resulting downloads from BIM360

But what’s the difference between these files? Are there particular publish settings that are required?

Well.. sort of.. you’ll kick yourself when you realise how simple it is, but then you’ll also be annoyed at how time consuming it could be on a large project.

Unload your links prior to publishing!

The model in the top screenshot is the 11mb model, it doesn’t have it’s links loaded and this is the way that it is published.

Meanwhile, the file with three links loaded is the 297mb model, so in reality the ZIP package could be much larger if all the links were currently loaded.

The problem I see with this is that with large projects, to achieve this you will need to unload the links, synchronise and then publish. That’s a lot of work when you have a lot of models but as always, there is potential to automate the mundane tasks.

But that’s a post for another time.

Clear Cache in Desktop Connector 13.x

Top tip from a co-worker, the new Desktop Connector 13.x allows you to clear the Desktop Connector cache, so if you’re someone that is limited on space or wants to clear up old project data, then this is for you!

This isn’t the same cache as your C4R/BIM360 cloud model cache, but rather the cache of files from Desktop Connector. This cache would include items such as non-workshared RVT links, DWG, IFC, NWC links or other files that you have been accessing through desktop connector.

It’s a simple enough process to clear up the space, and unlike my C4R Cache Cleaner, you cannot delete individual files, it simply deletes the entire cache for a given project.

Right click on your project of choice, and from there the only menu option that you’re presented with is to free up space.

Confirm that you want to clear the cache and you’re away. Once you see the confirmation notification, you’re all done.

I personally only had 2.9gb of cache for this particular project, but others on my team are reporting upwards of 25gb of files they no longer needed locally cached.

Need to reclaim more space?

If you’re struggling with available space on your system and a hard drive upgrade isn’t an option, I highly recommend Space Sniffer if you’re on Windows. It gives an easy to follow visual representation of what is taking up space on your system and where.

You can take a visual deep dive through your folders to see where data is stored. Just keep in mind some things are critical to the operation of Windows and can’t be deleted, but if you have 7 versions of Revit installed for example, when you see how much room they take up it might finally give you the nudge that you need to uninstall a few versions that you no longer use.

Help! My BIM360 Desktop Connector Icon Has Disappeared!

Over the years I’ve experienced that Autodesk’s Desktop Connector can at times be a little finicky after updating. With the release of the new version 13.x things seem to be no different.

The most common issue I’ve experienced when updating desktop connector is for the BIM360 icon to disappear from Windows Explorer.

So if this happens, how do we get the icon back? Here are a few things you can try from least destructive to most destructive.

Refresh Your Drives

First, try to refresh your drives. This only refreshes your Autodesk related “drives” and will not affect anything on your local machine or your network.

Right click on the Desktop Connector icon and select Refresh Drives from the menu.

It works some of the time, but not that often. Not a problem though as there are more things to try.

Log out and in again

As simple as it sounds, this is always the first thing you should try. It’s quick and easy and will sometimes get the job done.

Right click on the Desktop Connector icon in the task bar and select Sign Out from the menu. Once Signed out, sign back in. Simple.

Delete Your Desktop Connector Cache

Ok, so now we’re getting.. sort of.. serious. Deleting things!

First, log out of Desktop Connector and close it.

Next, head to the following folder:

%localappdata%\Autodesk

Or if you want to browse manually, this will be C:\Users\<your user name>\Local\Autodesk and look for a folder that looks like the one highlighted below

Delete this folder. Alternatively if you’re a bit worried about the results of deleting the folder, rename it so that it’s suffixed with .old

Our next step is to head to the folder

%localappdata%\Autodesk\Web Services

Delete the Desktop Connector folder under Web Services.

Do not delete the Desktop Connector folder from the folder in the previous step!

Restart Desktop Connector by launching it from the start menu. You will see the “Welcome to Desktop Connector” dialogue.

Close the window and wait for a few more seconds and your BIM360 icon should reappear!

Reinstalling Desktop Connector

On the very rare occasion, even after following these steps you still won’t see the BIM360 icon, you’re going to have to reinstall desktop connector.

The correct way to reinstall is to follow the steps above to clear out the Desktop Connector cache.

Once the cache has been cleared, uninstall desktop connector and restart your computer.

Once the computer has been restarted you can then reinstall Desktop Connector and everything should work once more.

What if I still can’t see it?

In my experience the above steps should be all you need to take. If you’re still not able to see the icon there is one step left that might fix it..

C4R (and BIM360) Cache Cleaner Tool

Alrighty, calm down! I know C4R is the old and BIM360 is what we mostly work with now, but it was a long time ago when I created this handy little tool.. and “BIM360 Cache Cleaner” doesn’t quite have the same ring to it.

You might remember a post I made a while back about how to manually clean out your C4R (now BIM360) cache. It’s a rare occurrence but on sometimes you end up with corrupt models in your local cache and you need to blow them away.

But explaining to the average user how to clear these models by searching journals and digging through their appdata folder, not to mention don’t forget your PacCache folder.. man.. it’s hard work!

As I’ve been getting involved in big projects again, I’ve already had two instances where I have had corrupted local files. This could be caused by all sorts of things, but I find usually the culprits are

  • Dropped internet connection during open or sync
  • Project partners running different patch versions of Revit (i.e. 2020.1 and 2020.2.1)
  • Corrupt family elements

Realistically though it could be caused by any number of bad Revit practices and the bigger the project, well, the more chance you’re going to stumble across things that break models.

All that aside though, a long time ago I decided to create a tool that would assist with this local cache cleaning process, and as I’ve found that I’ve needed to use it recently, I thought I would provide it free of charge for anyone that might find it useful.

It’s pretty easy to use, and it’s premise is simple. C4R Cache Cleaner is a standalone program that reads the journal files saved on your local machine to discover local copies of BIM360 files stored on your machine.

It won’t tell you what models are corrupt, and it doesn’t save a list of files that you’ve opened over time. If the project or the file isn’t found in a journal file.. well.. it just won’t show up.

The reason for this is that when you want to fix up a locally corrupted model, it’s something that you have been working on just now. There is no point to over complicate the tool to record a history of models through Revit addins and other fun stuff.

Most people should be able to figure out how to use the tool without any further instruction, but just in case you want a little more direction on how to clean your cache, I present you with probably the least pretty diagram I’ve created.

Hopefully someone else out there will find this little tool helpful, I know I do.. but I’m kind of biased.

Download

Think this tool is worth something? Consider donating to support the operation of the site and the development of further tools in the future.

Understanding the British Standard Object Naming Convention and Other Alternatives

Unless you’ve been living under a rock for the last few years, you’d be aware that almost globally the British Standards are the benchmark for all things BIM.

The international standard ISO19650 is based on the British BS and PAS1192 documents. Most naming conventions out there are based on BS 8451-1:2012. BS8451-1 covers naming and classification of BIM objects for architectural and engineering and construction. Natspec Open BIM Object Standard (OBOS), ANZRS? Yep you guessed it. They’re based on or derived from BS 8451.

Naming Options

There are two options in the British Standard. Objects that contain classification parameters and objects that don’t. What does this mean for you though? In it’s most basic sense if you drop the required classification information into parameters within the objects themselves, then you can have far simpler object names.

Don’t want to populate classification parameters? Well you’re naming content the long way.

Objects that contain classification attributes

If your object contains classification information within parameters, you don’t need to repeat that information in the family name. Providing data just because technology allows you to isn’t the right way to approach BIM.

BS8451-1 calls for “at least one classification to a UK convention” or “a classification from an equivalent generic classification text” so if you’re using Uniclass, Omniclass, Master Spec, it doesn’t matter as long as it is what your client has requested or you project team has agreed to.

The source or author is the library author, such as a company or the manufacturer themselves. This could be an abbreviated code, or it could be the full name.

It’s also not both the author and the manufacturer, it should be one or the other. It is who created the content. If the manufacturer had their content created by a third party, this is when it should the the manufacturer’s name or abbreviation. And if you’re not sure how to abbreviate your company name, if they’re listed on the stock exchange, that’s a good place to start!

The type is the first level of specialisation. A lot of people in the Revit world make the mistake of this being the Revit family category, which if we come back to the concept of “don’t repeat information just because you can” if you use the category as the type portion of the name, you’d missed an opportunity.

The subtype or product is optional but in my opinion it’s quite useful. It’s used to convey information not captured in attribute data.

An example of an object named in this manner could be my floorwaste gully family. In this instance the name might be:

RAU_Floorwaste_Iplex

Or say in the instance of a surface mount troffer lighting fixture, you might name it:

Acme_LightFixture_SurfaceMountTroffer

or better yet because our objects are already categorised, we can skip “LightFixture” from the name and run with something like this:

Acme_Troffer_SurfaceMount

In each instance, the remainder of the classification information and any other required information is contained within the object itself.

Objects that do not contain classification attributes

So this is where the naming can get tricky, and oddly enough much of the content I’ve seen over the years uses this long form of naming or some hybrid of this system to name their content, even if the object contain relevant classification parameters.

There isn’t a problem with this, if you want to use the long form naming convention that’s great, but just remember you want to keep your content and it’s naming simple and easy so your team is more likely to use it.

For these kinds of objects, the standard adds extra information to the front end of the object name.

The role is the role of the object owner on the project based upon the BS1192:2007 requirements for defined roles and responsibilities, for example LB for library provider and MN for manufacturer.

The classification is the coding from the classification system that your client has requested or the project has agreed to. Using my previous content examples

Floor waste:

Classification SystemClassification Code
UniclassPr_65_52_25
Omniclass23-31 27 00
Masterspec7151

Lighting fixture:

Classification SystemClassification Code
Uniclass Pr_70_70_48_85
Omniclass 23-35 47 11 11 11
Masterspec7741

BS8541-1 also permits the text description of the classification code to be included and separated by a colon, for example: Pr_70_70_48_85:Surface luminaires

Presentation is optional and describes the level of detail that the object is presented in.

The remainder of the fields remain the same, covering the Source or Author, Type and Subtype or Product.

Using the same families again, using this long form approach the families would be named as follows:

LB_Pr_65_52_25_LOD300_RAU_Floorwaste_Iplex

and for the lighting fixture

MN_ Pr_70_70_48_85_LOD200_Acme_Troffer_SurfaceMount

The ANZRS Method

The ANZRS method to object naming is

It’s arguably more agreeable naming convention as the first portion of the name has no risk of becoming an endless list of redundant company abbreviations that make it impossible to search for object alphabetically.

The FunctionalType portion of the name is the broadest descriptor that can be used. In the example of our floorwaste, that would be FloorWaste. It’ is made very clear in the ANZRS documentation that the functional type or the type have nothing to do with the Revit family category.

The Subtype contains the next logical level of information to descibe the element. In the example of my floor waste, I would want to know what kind of material it is made from, so I would use PVC.

This might vary greatly depending on the type of object and the kind of information you wish to convey.

The Manufacturer is obvious, if the object is intended to be generic, then simply enter Generic.

Descriptor is entirely optional, but it’s where you can provide additional information to help describe the object.

As with other naming conventions there are no allowances for spaces or hyphens. Underscores should be used to separate descriptors and multiple word descriptors should use PascalCase.

Using our same objects as examples again, using ANZRS they would be named as follows:

Floorwaste_PVC_Iplex and

LightFixture_Troffer_Acme_SurfaceMounted or more in line with the ANZRS descriptors would be:

Troffer_SurfaceMount_Acme_Flourescent65w

Natspec OBOS

The Natspec Open BIM Object Standard flips the BS8541-1 naming on it’s head in the same way ANZRS does, but OBOS gets a little more descriptive.

The Type, Subtype and Source are the same as the ANZRS functional type, type and manufacturer.

OBOS then continues to add further descriptors, starting with Product/Range Identifier which is used to identify the manufacturer’s product range or product identifier. This could be a part number.

The Differentiator is to provide additional information as required to describe the object or it’s material.

Finally, the Originator is a 3-6 character code to indicate who has authored the object.

Again taking our same families, they would now be named

Floorwaste_PTrap_Iplex_PVC_RAU and

LightFixture_Troffer_Acme_Flourescent65w_SurfaceMounted_ACME

Which is right for me?

As I’ll always argue, you need to make it easy for the team working with the content. In my opinion don’t overload the naming convention with coded abbreviations, especially if you’re using teams overseas.

My main two arguments when naming content will always be:

  • Don’t prefix your content with your company name or the author name (sorry BS8541, you’re doing it wrong). Not every company has a content management system to make searching easier. If you’re using Revit or file explorer to search for content, drop the author/company descriptor to the back of the filename like they do in ANZRS or OBOS.
  • Don’t waste your type or subtype descriptors by using the Revit family category. Use something that actually adds value to your content naming rather than something redundant. Again, it needs to be something that is easy to find without a content management system. Revit already sorts content by family category, adding that family category to the name of the object is a waste.

Another consideration to working with teams overseas and content naming, make sure that you understand some of the nuances in their use of English. For example, the Philippines is Americanised so many of the terms used in Australia or Europe may not be directly understood without explanation.

At the end of the day, it’s whatever works for you and your team. Make sure the naming convention is discussed with all stakeholders, that everyone can come to a compromise for the greater good.

Finally, make sure that it is all adequately documented so that anyone can jump in and understand what is going on.

View References. Use them!

So even though in the BIM world we produce models, guaranteed every project that you’re currently working on you’re also contractually obliged to produce drawings.

Drawings require things like notes and symbols, legends and linestyles.. and sheet or view references.

When you have a large architectural background or piece of linear infrastructure, you need to split your plans up over multiple sheets. When this happens, it’s best practice to include a sheet reference so whoever is reading the drawing knows where to go to keep on reading.

Usually this is common sense, it’s the next sheet in the drawing set. Even when this is the case though, you still need to provide a sheet reference.

With all the data you have at your fingertips in the model, for some reason people still insist on using text notes. That’s dumb text for those playing at home.

So let’s paint a picture. You’re working on a piece of linear infrastructure, and there is now a requirement for an additional 3 or 4 drawings at the front end of the set. You have text notes to update, across 58 drawings!

Why are you torturing yourself (and me)?

Use view references. They’re a handy dandy little family type that you can reference the view itself, which then provides the sheet number that the view resides on. If the drawing numbers change, then everything is updated automatically. No need to edit dumb text notes.

It might seem like a chore when you first set it all up and link the references to the correct views, but then for the rest of the project it’s smooth sailing. Why make life harder for yourself in the long run?

Don’t get mad. Get view referencing.

After fixing up an entire series of drawings and sending a few astounded and frustrated messages to some mates over WhatsApp (sorry guys!), I got to the end of my list of views and realised there was an out of sequence view.

Ignoring that there is clearly an extra step in the scope box naming vs. the view naming, the very last view in the list “Sheet 37” had scope box 23 applied to it.

Well.. no need to get mad, after renaming the incorrect views in Excel and slipping the new view 24 into the sequence, I only had to fix up the view references on views 23 and 25 to reference the new 24 and create the new references on view 24.

Could you just imagine if you had to fix that up if it was a dumb text note? Especially after you had just run through the entire sequence of views.

I’d be channelling my inner Moss.

Revit 2020.1 Prompts to uninstall when you want to install

This is one I have unfortunately come across too many times, you notice that you can’t access BIM360 in Revit 2020, you check your version and you have plain old 2020 which is before the critical TLS patch was released. Easy, I’ll install the 2020.1 patch.

But Revit says no. Update to 2020.2 right? Well.. no. The project you’re working on for the short term is locked into 2020.1 to keep versions consistent. So what are we going to do?

Well, thankfully there are a lot of helpful people out there on the big wide world of the internet, for this one Tony Michniewicz posted up the solution on the Autodesk Support Forums

Open REGEDIT, you will need admin rights for this one. Even local admin rights will do.

The browse to the following registry key

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\

Once there, right click on the key and select find from the contextual menu and search for Autodesk Revit 2020.1.

When you find the existing registry key, simply delete it and then re-run the 2020.1 installer.

Nested Annotation Symbols 101

Over the years, I’ve seen some interesting Revit content. One of the doozies though always seems to be the use of nested annotations and for whatever reason, these weird and wonderful annotation solutions always seem to be in electrical families.

The idea of nesting an annotation symbol in a 3D family is so you can present both a “real life” display for coordination purposes and a symbolic representation for your drawings.

There is no need to get creative with visibility controls

At their most basic level, nested annotations should be controlled by the coarse/medium fine visibility settings.

Simply select the nested annotation in the 3D family, click the visibility/graphics ovverides button in the properties dialogue and then choose when you want the symbol to appear. Generally at fine mode the symbol would be switched off, coarse and medium you should follow your company standards. As the detail level of the view changes, the visibility of the symbol follows suit.

I’m not here to stifle creativity, far from it. But if you’re setting up families and you feel like you’re having to come up with creative solutions for simple things like the display of symbols, chances are you’re doing it wrong.

Yes/No check boxes instead of detail level. Just don’t do it.

In the above example, the family has an instance based Yes/No visibility parameter. This is painful for not only the the end user to work with, but could you imagine giving a model configured this way to an architect and then explaining to them if they need to coordinate on ceiling equipment they need to turn off a series of instance parameters to do so? Yeah nah.

Maybe the more frustrating thing about this particular example is that the 3D components of the family are not controlled at various detail levels either. If you have the symbol on, both the 3D and 2D content is visible all the time which in turn results in your graphical display on drawing to get a bit weird.

Take this example below, how will a contractor on site be able to tell what this even is once printed as a hard copy?

Unfortunately there is no way to be nice or beat around the bush about this one. Just use the provided built in detail level controls in your families. It’s not even difficult to use!

That old annotation orientation chestnut

As a hydraulic guy, I’m rather jealous of the maintain annotation orientation option that electrical and comms families have so I’m sure you understand when I get a little upset with some content creator’s solution to symbology display in families that need to be oriented differently depending on the particular scenario.

The brilliance of this option is that regardless of the rotation of your family, the symbol will display correctly. Need a power outlet on a wall, in a floor box or on the ceiling? No need for multiple families or content creation trickery! Just tick the box!

Upside down, back to front, sideways, no matter what you’ve got the annotation will always appear correctly!

Movable annotation symbols

I’ve talked about movable annotation symbols a long long time ago, and let’s face it, they’re pretty great. But they have a time and place; usually for power and data outlets and the like.

Where they should never be used are things where the symbol is normally shown at actual object size, and is in fact a detail item, not an annotation symbol. Objects such as pits, lights, air terminals.. that’s all a big no for movable annotation symbols.

Why though? Well sit down, pour yourself a drink, grab some popcorn and let me tell you about a story of terrible coordination..

Flip it round

The last common problem that I have seen with content is the use of flipped and mirrored family symbol variations. This particular example is my favourite as well, you see the symbol is supposed to flip by turning on/off the alternate symbol.. but it looks like someone forgot to do that.

Forgetfulness aside, there is a method that can be used particularly for these 3D families that have consistent geometry built of a revolve.

Adding a flip in the direction it’s required will flip both the annotation symbol and the geometry, so just be careful when you use it. In the above example of the smoke detector, the flip control is no drama but in the instance of something such as a power outlet on a wall, using the flip will flip the geometry into the wall itself.

I would however ask the question, is the flip actually required on the symbol? What value does the flippable symbol add to your template? Avoid adding unnecessary complexity or configuration wherever possible in content, especially where standardisation is key. If there are options available on symbol display, then it’s not standard.

Up, Down, Up, Down.. and left and right.

I often see this in families that contain text in the symbol. Some variation of instance based yes/no visibility check boxes to show a correctly oriented symbol and text.

The example above actually relies on a combination of the left and front visibility check boxes to in turn display the correct symbol. The other more obvious variation of this solution that I’ve seen is the literal up, down, left, right parameters. Either way, it’s what we in the industry call a shemozzle.

As with most of these other creative solutions, there is actually an out of the box solution to handle the orientation of text within symbols.

The keep text readable option does just that, it keeps the text readable in line with standard drafting practices of the text being readable from the bottom or the right hand side of the page.

As you can see in the example, I have created a simple arrow family to clearly display the direction the family itself has been rotated. The symbol itself is a nested annotation with text and linework for the box.

With the annotation family correctly configured with the keep text readable tag, the text always appears correctly without introducing the possibility of human error.

Do you have any other tips on working with nested annotations in Revit families? If so post them in the comments section below

The Drawing Status

The drawing status is maybe overlooked as something simple, but there are many different ways to approach it, some being more cumbersome to mange than others.

Checkboxes

First we have the instance based checkbox. It’s a great method if you have something like Ideate BIMLink available to you, or a well developed Dynamo graph, but if you don’t have either of these then the manual checking of boxes across a project becomes tedious quite quickly.

Even with these tools to speed up your work, setting the status of these titleblocks can become quite the chore if you have a lot of statuses to work with like the above example and you have differing statuses from sheet to sheet.

rows and rows and columns and columns and rows and rows..

Even though you can copy cells in Excel, I wouldn’t want to be the person given the task of ensuring the accuracy of these status stamps.

So how do we improve on this?

Integers

The next approach to managing instance based on/off visibility, the integer. I’ve discussed the use of integers to control visibility in the past and it certainly makes management of visibility much easier.

As you can see in the above example, we have a single integer value controlling the visibility of all the status options. As you can see, we have a series from 1-10 and another series from 21-28, this is differentiate between statuses in different geographical regions. But we can do better than that!

Although it’s slightly more complex and gives an additional integer to define, if you have consistent statuses between regions that need to be displayed differently, then you have the benefit of both regions having the same status code, such as 4 for tender issue.

Sure you need to either have a list in front of you or at least remember what number corresponds to which status, but both of these solutions are much easier to manage in an Excel based workflow as you simply need to export one or two parameters in addition to the sheet number.

Another simple alternative to controlling the region setting is to have the integer as a type based parameter and create a titleblock type per region or office, that way there is no need for the end user to set the integer controlling the region within the titleblock at all.

Checkboxes and Family Types

The family type parameter method is another way to approach this simple task, however it makes things a little trickier as the parameters aren’t easily manipulated with BIMLink.

Often I’ve seen titleblocks using this method to still use yes/no visibility check boxes within the nested family. The nested family types can then be controlled using an instance parameter in the titleblock, which provided that you name your nested family types in a simple easy to understand manner, it gives the end user an easy to understand way to control the status on a per sheet basis.

The Free-for-all Instance Label

An option that is rarely used and probably for good reason is the free-for-all label. This is where the status is controlled by an instance text parameter tied to a label in the nested annotation family. The instance parameter is then linked through another instance parameter to the status family.

As status stamps are something that are standardised and shared parameter labels by their nature are a free for all text box, it’s a good reason to not use a label. However, if you have a good BIM or drafting lead overseeing the project and ensuring the correct standards are being applied, then there is no reason why using labels should be out of the question. There will always be that risk of inconsistency though.

Labels and Family Types

Finally, probably the best option is the nested annotation symbol with a label that is controlled by a type parameter. This method is both easily controllable in an Excel or Dynamo based workflow and is a clean and lightweight option.

Regardless of the method you choose, make sure it’s easy for the end users to adopt and if there is anything at all that needs to be documented, make sure it’s documented clearly and concisely.

From Dynamo to C# – Get and Set Parameters

I’m the kind of guy that uses Dynamo for practical things, an indispensable swiss army knife that I used to manipulate data.

Getting and setting parameters is obviously key. This time around we look at how this is done in Dynamo and then how we can achieve that same thing with code.

In this example I will look at how to build up an asset code based on the level name and the mark parameter, combining those into a single new parameter value.

We will start with the code from the previous Dynamo to C# post where we collected all the AHU families in the model. For convenience, here is the complete code from the previous post:

public void getMechanicalEquipment()
{
	//get current document
	Document doc = this.ActiveUIDocument.Document;
	
	//setup collector and filter
	var collector = new FilteredElementCollector(doc);
	var filter = new ElementCategoryFilter(BuiltInCategory.OST_MechanicalEquipment);

	//collect all mechanical equipment
	var allMechanicalEquipment = collector.WherePasses(filter).WhereElementIsNotElementType().Cast<FamilyInstance>();

	//use LINQ to filter for familyInstances containing AHU in the family name
	var ahuEquipment = from fi in allMechanicalEquipment
		where fi.Symbol.FamilyName.ToUpper().Contains("AHU")
		select fi;

	//setup string builder to store data
	StringBuilder displayInfo = new StringBuilder();

	//loop through, collect data
	foreach (FamilyInstance fi in ahuEquipment)
		{
			var elementinfo = string.Format("Family Name: {0} Element Id: {1}", fi.Name, fi.Id);
			displayInfo.AppendLine(elementinfo);
		}

	//display results
	TaskDialog.Show("Watch", displayInfo.ToString());
}

Getting the Level

To do this in Dynamo, you would need to string together the following nodes:

In Dynamo we need to use the Level.Name node to get the actual name. The reason for this is that when we feed Level into the Element.GetParameterByName node, the output is actually an element id. Feeding that element id into the Level.Name node returns the name without any further work required.

So how do we replicate this in C#?

First, we need to focus on the foreach loop, as this is where the work is done for each element that we have selected. We have already done the groundwork to select our elements, but how do we find out what level each element is associated with?

We need to use the level class from the API, this allows us to retrieve the name of the level as you would see it when inspecting the element you’re working with.

Using the level class, we create a variable theLevel which we find from the family instance fi.

Level theLevel = fi.Document.GetElement(fi.LevelId) as Level;

This line is doing half the work of our Level.Name Dynamo node. It is taking the element id of the level that is reported from the Level parameter of the selected AHU family, then selecting the level element.

From there we can simply use theLevel.Name to display the level name.

//loop through, collect data
foreach (FamilyInstance fi in ahuEquipment)
{
	Level theLevel = fi.Document.GetElement(fi.LevelId) as Level;
	var elementinfo = string.Format("Family Name: {0} Level: {1}", fi.Name, theLevel.Name);
	displayInfo.AppendLine(elementinfo);
}

Note that instead of using the elementinfo variable to display the family name element id of the AHU in the dialogue box as per the previous example, we are now displaying the family name and the associated level name.

Getting the Mark

There isn’t a whole lot of change between the process for picking up the mark parameter in Dynamo compared to the level name; the only real change is that we can drop the Level.Name node.

This is because when we tell the Element.GetParameterValueByName node that we want a parameter named Mark, it returns the result as a string.

In C# we want to use get_Parameter on the family instance fi.

But before we get too far, we need to understand that built in parameters are handled slightly differently in Revit to user defined parameters. Built in parameters are contained within an enumerated list, you can review the list of built in parameters on Revit API Docs.

In the API, the mark parameter is stored as ALL_MODEL_MARK

Retrieving built in parameters this way is more reliable as there is no risk that you will pick up a user defined parameter of the same name.

Now that we know this, our equivalent line of code to read the mark parameter in C# looks like this:

Parameter theMark = fi.get_Parameter(BuiltInParameter.ALL_MODEL_MARK);

But we still don’t have the parameter value. To retrieve the parameter value, we need to use the AsString method on our paramter theMark which will return the parameter value as a string.

It is important to use the correct method to avoid any potential errors returning the data, for numbers use AsDouble, for integers use AsInteger and element ids use AsElementId.

Our foreach loop should now look like so:

//loop through, collect data
foreach (FamilyInstance fi in ahuEquipment)
{
	//get the level
	Level theLevel = fi.Document.GetElement(fi.LevelId) as Level;
	//get the mark
	Parameter theMark = fi.get_Parameter(BuiltInParameter.ALL_MODEL_MARK);

	var elementinfo = string.Format("Family Name: {0} Level: {1}", fi.Name, theLevel.Name);
	displayInfo.AppendLine(elementinfo);
}

Again, adding this to our task dialogue, we end up with the following results.

Building the New String

We can build our new parameter value a few different ways in Dynamo, either by using the String.Concat node, or by using a code block which is my preferred method.

There are also a few different way you can approach building the new string in C# as well. The simplest way is to approach it the same way as we do in the Dynamo code block.

First you define the string, in this example we are naming it newValue and we take our level name theLevel.Name, add the string _AHU_ and the we take our mark value with theMark.AsString().

string newValue = theLevel.Name + "_AHU_" + theMark.AsString();

The other method is to use a string builder which we have been using in our examples to create our dialogue box message. The string builder version would look like so:

var newValue = string.Format("{0}_AHU_{1}", theLevel.Name, theMark.AsString());

Either method is acceptable, but if you’re building more complex strings the string builder is the recommended way to go. Both options give the exact same results:

Setting the New Parameter

In Dynamo, the job here is done by the trusty Element.SetParameterByName node seen above, but in C# there is a tiny bit more to do.

The first thing we need to do to set out parameter is define which parameter we want to set. In this example I’m going to use the built in parameter Comments which is stored in Revit as
ALL_MODEL_INSTANCE_COMMENTS.

Parameter theComments = fi.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS);

The next step is to start a transaction. Every time you want to change something in a Revit file via the API, you need to make the changes inside a transaction. If you have ever looked into Dynamo nodes containing Python code, you would have seen something similar to this before.

//set the parameter
using(Transaction t = new Transaction(doc, "Set Parameter"))
{
	t.Start();
	//do stuff here
	t.Commit();
}

We define a new transaction t which is being performed in the current document doc which will appear in the undo/redo list as Set Parameter.

Inside our transaction, we set the parameter by using the Set method on our parameter theComments.

//set the parameter
using(Transaction t = new Transaction(doc, "Set Parameter"))
{
	t.Start();
	
	theComments.Set(newValue);
	
	t.Commit();
}

And that’s it! We have successfully pulled information from multiple parameters, generated new string data and set another parameter using C#.

The complete code is below:

public void getsetParameters()
{
//get current document
Document doc = this.ActiveUIDocument.Document;

//setup collector and filter
var collector = new FilteredElementCollector(doc);
var filter = new ElementCategoryFilter(BuiltInCategory.OST_MechanicalEquipment);

//collect all mechanical equipment
var allMechanicalEquipment = collector.WherePasses(filter).WhereElementIsNotElementType().Cast<FamilyInstance>();

//use LINQ to filter for familyInstances containing AHU in the family name
var ahuEquipment = from fi in allMechanicalEquipment
	where fi.Symbol.FamilyName.ToUpper().Contains("AHU")
	select fi;

//setup string builder to store data
StringBuilder displayInfo = new StringBuilder();

//loop through, collect data
foreach (FamilyInstance fi in ahuEquipment)
	{

		//get the level
		Level theLevel = fi.Document.GetElement(fi.LevelId) as Level;

		//get the mark
		Parameter theMark = fi.get_Parameter(BuiltInParameter.ALL_MODEL_MARK);

		//get the comments
		Parameter theComments = fi.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS);

		var newValue = string.Format("{0}_AHU_{1}", theLevel.Name, theMark.AsString());

		var elementinfo = string.Format(newValue);
		displayInfo.AppendLine(elementinfo);

		//set the parameter
		using(Transaction t = new Transaction(doc, "Set Parameter"))
		{
			t.Start();

			theComments.Set(newValue.ToString());

			t.Commit();
		}

	}

}