Help with registering EVENTS syntax for macro in C#

Help with registering EVENTS syntax for macro in C#

davidsUUGCH
Contributor Contributor
835 Views
9 Replies
Message 1 of 10

Help with registering EVENTS syntax for macro in C#

davidsUUGCH
Contributor
Contributor

I am working on a revit document macro that will help us get the username and central path when the document is exported or printed.

I need the 2 functions to trigger when a file is exported to DWF, printed or exported to DWG. (here i think revit views exporting anything as a single thing so maybe i nee only a single event for them).

 

I have tried adapting the initial solution i found online that worked for the first function to also trigger the second function. But now after i added the extra line refering the second function nothing happens.

 

Also i am not clear from what i have read and watched if the order of the written instruction affects when they are executed. I this case my first function is the one that reads the revit data and the second one will move the data to a sheet parameter that is read on the title-block.

 


Here is the simplified code:

namespace TESTMACRO7
{
    [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
    [Autodesk.Revit.DB.Macros.AddInId("EE6F0CDF-D1DC-4A32-A8F4-6959A1CA3B8E")]
	public partial class ThisDocument
	{
		private void Module_Startup(object sender, EventArgs e)
		{
		this.Application.Application.FileExporting += new EventHandler<Autodesk.Revit.DB.Events.FileExportingEventArgs>(CENTRALPATH_TO_CentralSTRG);
		this.Application.Application.FileExporting += new EventHandler<Autodesk.Revit.DB.Events.FileExportingEventArgs>(USERNAMETOX);
		}

		private void Module_Shutdown(object sender, EventArgs e)
		{
		this.Application.Application.FileExporting -= new EventHandler<Autodesk.Revit.DB.Events.FileExportingEventArgs>(CENTRALPATH_TO_CentralSTRG);
		this.Application.Application.FileExporting -= new EventHandler<Autodesk.Revit.DB.Events.FileExportingEventArgs>(USERNAMETOX);
		}

		#region Revit Macros generated code
		private void InternalStartup()
		{
			this.Startup += new System.EventHandler(Module_Startup);
			this.Shutdown += new System.EventHandler(Module_Shutdown);
		}
		#endregion 
		//*--------------- Function 1 omitted to make this easier to read -------------*
			internal void CENTRALPATH_TO_CentralSTRG(object sender, FileExportingEventArgs args)

      
	   //*------------------End Function 1--------------*
		//*-------------- Start Function 2 -------------*
        	public void USERNAMETOX (object sender, FileExportingEventArgs args)
	{
	        UIDocument uidoc = this;  
        	View view = uidoc.ActiveView;
        	
	 			//collect and set parameter. 
       			FilteredElementCollector collector = new FilteredElementCollector(uidoc.Document)
       				.OfClass(typeof(ViewSheet))
       				.WhereElementIsNotElementType();
                foreach(Element e in collector)
                {
                    foreach (Parameter p in e.Parameters)
                    {
                       if(p.Definition.Name=="CentralLocation")
                       {
                       	
                //Start transaction
                       	using (Transaction t = new Transaction(uidoc.Document,"Place family Instance"))
                       	  {
                       	    t.Start();
                //SetParameter
                p.SetValueString("GlobalParameter").ToString();
                            
                           t.Commit();
                       }
		}
	}
                }
        	}
	}
}

 

0 Likes
Accepted solutions (2)
836 Views
9 Replies
Replies (9)
Message 2 of 10

RPTHOMAS108
Mentor
Mentor

It is probably more to do with the code than the event.

 

Don't iterate all the parameters to find a single named one you are looking for

Don't use SetValueString to set a parameter of storage type string

 

You should also be aware that if you create a shared parameter and add it to a label in the title block family and also add it as a project parameter bound to the project information category then it will be global to the project. This means you only have to set the parameter once for it to be visible on all sheets.

 

using System;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI.Selection;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB.Events;

namespace TesdtModule
{
	[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
	[Autodesk.Revit.DB.Macros.AddInId("06D2BB11-C92D-4AA3-8C35-F68988A0580D")]
	public partial class ThisDocument
	{
		private void Module_Startup(object sender, EventArgs e)
		{
			this.Application.Application.FileExporting += new EventHandler<FileExportingEventArgs>(USERNAMETOX);
		}

		private void Module_Shutdown(object sender, EventArgs e)
		{
			this.Application.Application.FileExporting -= new EventHandler<FileExportingEventArgs>(USERNAMETOX);
		}

		#region Revit Macros generated code
		private void InternalStartup()
		{
			this.Startup += new System.EventHandler(Module_Startup);
			this.Shutdown += new System.EventHandler(Module_Shutdown);
		}
		#endregion



		public void USERNAMETOX (object sender, FileExportingEventArgs args)
		{
			UIDocument uidoc = this;
			View view = uidoc.ActiveView;

			//collect and set parameter.
			FilteredElementCollector collector = new FilteredElementCollector(uidoc.Document)
				.OfClass(typeof(ViewSheet))
				.WhereElementIsNotElementType();
			foreach(Element e in collector)
			{
				
				Parameter Param = e.LookupParameter("CentralLocation");
				if (Param !=null)
				{
					//Start transaction
					using (Transaction t = new Transaction(uidoc.Document,"Place family Instance"))
					{
						t.Start();
						//SetParameter
						Param.Set("GlobalParameter");

						t.Commit();
					}
				}
				
				
				
			}
		}
	}
}

 

 

 

 

 

0 Likes
Message 3 of 10

davidsUUGCH
Contributor
Contributor

I am not sure what you mean.

 

the key issue is that i need to connect the Global Parameter to the shared Parameter. This is not possible via API as the function i found this (https://www.revitapidocs.com/2023/796f3d95-956e-a2a9-7f8e-e8efd2a0eea0.htm) to connect a shared parameter to a global parameter does not seem to take a sheet as target so i cannot use it.

 

So i tried the long way.

This is set up to extract data from the model AKA the central file path

Then it sets that as a string into a Global Parameter

Then it attempts to read the Global Parameter value and set the Project Parameter to that value.

 

Here is the whole thing:

namespace TESTMACRO7
{
    [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
    [Autodesk.Revit.DB.Macros.AddInId("EE6F0CDF-D1DC-4A32-A8F4-6959A1CA3B8E")]
	public partial class ThisDocument
	{
		private void Module_Startup(object sender, EventArgs e)
		{
		this.Application.Application.FileExporting += new EventHandler<Autodesk.Revit.DB.Events.FileExportingEventArgs>(CENTRALPATH_TO_CentralSTRG);
		this.Application.Application.FileExporting += new EventHandler<Autodesk.Revit.DB.Events.FileExportingEventArgs>(USERNAMETOX);
		}

		private void Module_Shutdown(object sender, EventArgs e)
		{
		this.Application.Application.FileExporting -= new EventHandler<Autodesk.Revit.DB.Events.FileExportingEventArgs>(CENTRALPATH_TO_CentralSTRG);
		this.Application.Application.FileExporting -= new EventHandler<Autodesk.Revit.DB.Events.FileExportingEventArgs>(USERNAMETOX);
		}

		#region Revit Macros generated code
		private void InternalStartup()
		{
			this.Startup += new System.EventHandler(Module_Startup);
			this.Shutdown += new System.EventHandler(Module_Shutdown);
		}
		#endregion
			internal void CENTRALPATH_TO_CentralSTRG(object sender, FileExportingEventArgs args)
					
				{
        	UIDocument uidoc = this;  
        	View view = uidoc.ActiveView;
        	
        	
    		// collect the titleblock and the parameter extract central path  
    		var ModelPath = uidoc.Document.GetWorksharingCentralModelPath();
    		string CentralServerPath = ModelPathUtils.ConvertModelPathToUserVisiblePath(ModelPath);
        	string titleBlockFamilyTypeName = "D 22 x 34 Horizontal";  
        	string parameterName = "CentralSTRG";
  
        	FamilyInstance titleBlock = new FilteredElementCollector(uidoc.Document, view.Id)  
            	.OfCategory(BuiltInCategory.OST_TitleBlocks)  
            	.OfClass(typeof(FamilyInstance))  
            	.Cast<FamilyInstance>()  
            	.Where(f => f.Name == titleBlockFamilyTypeName)  
            	.FirstOrDefault();
        	
        	
			//set the parameter to central file path. 
        	using (Transaction tr = new Transaction(uidoc.Document))  
        	{  
            	tr.Start("set GlobalParameter");  
				
             	ElementId globalParameterId = GlobalParametersManager.FindByName(uidoc.Document, parameterName);
				GlobalParameter globalParameter = (GlobalParameter)uidoc.Document.GetElement(globalParameterId);
				ParameterValue parameterValue = new StringParameterValue(CentralServerPath);
				globalParameter.SetValue(parameterValue);

            	tr.Commit();  
        	}
			}
        	public void USERNAMETOX (object sender, FileExportingEventArgs args)
	{
	        UIDocument uidoc = this;  
        	View view = uidoc.ActiveView;
        	
	 			//collect and set parameter. 
       			FilteredElementCollector collector = new FilteredElementCollector(uidoc.Document)
       				.OfClass(typeof(ViewSheet))
       				.WhereElementIsNotElementType();
                foreach(Element e in collector)
                {
                    foreach (Parameter p in e.Parameters)
                    {
                       if(p.Definition.Name=="CentralLocation")
                       {
                       	
                //Start transaction
                       	using (Transaction t = new Transaction(uidoc.Document,"Place family Instance"))
                       	  {
                       	    t.Start();
                //SetParameter
                p.SetValueString("GlobalParameter").ToString();
                            
                           t.Commit();
                       }
		}
	}
                }
        	}
	}
}

 

 

0 Likes
Message 4 of 10

RPTHOMAS108
Mentor
Mentor
Accepted solution

I'll look again.

 

However if the aim is to store the central file location etc. in a global parameter and then copy that value into each sheet parameter then this is unnecessary.

 

Shared parameters bound to the project information singleton are available to use as labels in the title block family if the same shared parameter has been added to that title block family also.

 

All you would have to do then is update the shared parameter on the project information singleton via the macro export event. That is this task is no different to accessing other information on the project information element via the title block such as site address.

 

The examples I've seen linking global parameter to other parameters in the project are related to parameters of model elements e.g. the door swing example. Can you do one cycle of your intended automation task manually via the UI? If the answer is no then it is unlikely the API will support it either. I'm sure the API will allow you to copy a global parameter value into a sheet parameter but I'm also sure there is a better alternative for what I think you want to do.

Message 5 of 10

davidsUUGCH
Contributor
Contributor

I re read the solution and i should add i started using the shared parameter alone as you suggested but i could not get the code to work. Then someone suggested i should use a global parameter as this will make the code work outside C#. So  started to work it that way. Got the code working with the global parameter but then i hit a road block trying to link it to the original shared parameter.

 

Maybe i should look at the old code.

 

Looking back at the old code:

namespace TestMacro5
{
    [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
    [Autodesk.Revit.DB.Macros.AddInId("44DC398D-02D1-4883-9F4C-CA13E178BA72")]
	public partial class ThisDocument
	{
		private void Module_Startup(object sender, EventArgs e)
		{
		this.Application.Application.FileExporting += new EventHandler<Autodesk.Revit.DB.Events.FileExportingEventArgs>(CENTRALPATH_TO_CentralSTRG);
		}

		private void Module_Shutdown(object sender, EventArgs e)
		{
		this.Application.Application.FileExporting -= new EventHandler<Autodesk.Revit.DB.Events.FileExportingEventArgs>(CENTRALPATH_TO_CentralSTRG);
		}

		#region Revit Macros generated code
		private void InternalStartup()
		{
			this.Startup += new System.EventHandler(Module_Startup);
			this.Shutdown += new System.EventHandler(Module_Shutdown);
		}
		#endregion
				internal void CENTRALPATH_TO_CentralSTRG(object sender, FileExportingEventArgs args)
					
				{
        	UIDocument uidoc = this;  
        	View view = uidoc.ActiveView;
        	
        	
    		// collect the titleblock and the parameter extract central path  
    		var ModelPath = uidoc.Document.GetWorksharingCentralModelPath();
    		string CentralServerPath = ModelPathUtils.ConvertModelPathToUserVisiblePath(ModelPath);
        	string titleBlockFamilyTypeName = "D 22 x 34 Horizontal";  
        	string parameterName = "CentralSTRG";
  
        	FamilyInstance titleBlock = new FilteredElementCollector(uidoc.Document, view.Id)  
            	.OfCategory(BuiltInCategory.OST_TitleBlocks)  
            	.OfClass(typeof(FamilyInstance))  
            	.Cast<FamilyInstance>()  
            	.Where(f => f.Name == titleBlockFamilyTypeName)  
            	.FirstOrDefault();
        	
        	
			//set the parameter to central file path. 
        	using (Transaction tr = new Transaction(uidoc.Document))  
        	{  
            	tr.Start("setting titleblock parameter");  

             	titleBlock.GetParameters(parameterName).FirstOrDefault().Set(CentralServerPath);  

            	tr.Commit();  
        	}  
		}
	    }}

 

Message 6 of 10

RPTHOMAS108
Mentor
Mentor
Accepted solution

Enclosed is a project file in 2019 format with document macro that sets a parameter upon file export.

 

The parameter has guid as in the shared parameter file and this is what you use to obtain the parameter.

 

I would probably have done this via an Addin to be honest i.e. to encompass every document not just one or those derived from a certain template.

 

221018.PNG

 

using System;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI.Selection;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB.Events;

namespace General
{
	
	[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
	[Autodesk.Revit.DB.Macros.AddInId("06D2BB11-C92D-4AA3-8C35-F68988A0580D")]
	public partial class ThisDocument
	{
		private void Module_Startup(object sender, EventArgs e)
		{
			this.Application.Application.FileExporting += new EventHandler<FileExportingEventArgs>(USERNAMETOX);
		}

		private void Module_Shutdown(object sender, EventArgs e)
		{
			this.Application.Application.FileExporting -= new EventHandler<FileExportingEventArgs>(USERNAMETOX);
		}

		#region Revit Macros generated code
		private void InternalStartup()
		{
			this.Startup += new System.EventHandler(Module_Startup);
			this.Shutdown += new System.EventHandler(Module_Shutdown);
		}
		#endregion

		public string Mpath ()
		{
			
			if(this.Document.IsWorkshared)
			{
				
				string MP =ModelPathUtils.ConvertModelPathToUserVisiblePath(this.Document.GetWorksharingCentralModelPath());
				return MP;
				
			}
			else
			{
				return this.Document.PathName;
			}
		}
		
		

		public void USERNAMETOX (object sender, FileExportingEventArgs args)
		{
			UIDocument uidoc = this;
			View view = uidoc.ActiveView;

			//collect and set parameter.
			FilteredElementCollector collector = new FilteredElementCollector(uidoc.Document)
				.OfCategory(BuiltInCategory.OST_ProjectInformation)
				.WhereElementIsNotElementType();
			
			Element El = collector.FirstOrDefault();
			
			if (El != null)
			{
				Parameter Param = El.get_Parameter(new Guid("10601109-6881-4190-b5f6-22dbe61cca7b"));
				if (Param !=null)
				{
					//Start transaction
					using (Transaction t = new Transaction(uidoc.Document,"Place family Instance"))
					{
						t.Start();
						//SetParameter
						string MP = Mpath();
						
						Param.Set(MP);

						t.Commit();
					}
				}
			}
			
			
		}
	}
}

 

 

 

Message 7 of 10

davidsUUGCH
Contributor
Contributor

Thanks. I want to take this an APP. But i am really new at this (about a month). I tried making it an APP but encountered several issues. So i keeping it as an macro for now and try and get more proficient with C# and API.

 

I have a questions in line 46 on the code you provided i see this:

Document.PathName

So i gather if the project is A360 will this be filled or will it give an error? I was told not to worry about A360 since it has its own management protocols too see who prints what we don't need to implement this control.

 

I know you can select a shared parameter by using the GUID but is the shared parameter GUID the same for all the projects? i seem to recall reading that the GUID for shared parameter changed project to project.

 

I managed to get it to work. Using only the Shared parameters. Here is the code (this is my current code, it will not compile due to experimenting adding a second application event trigger:

 

namespace TESTMACRO9
{
    [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
    [Autodesk.Revit.DB.Macros.AddInId("116333E3-4778-4029-BD9C-4EAF4FEF5C03")]
	public partial class ThisDocument
	{
		private void Module_Startup(object sender, EventArgs e)
		{
		this.Application.Application.FileExporting += new EventHandler<Autodesk.Revit.DB.Events.FileExportingEventArgs>(CENTRALPATH_TO_CentralSTRG);
		this.Application.Application.DocumentPrinting += new EventHandler<Autodesk.Revit.DB.Events.DocumentPrintingEventArgs>(CENTRALPATH_TO_CentralSTRG);
		}

		private void Module_Shutdown(object sender, EventArgs e)
		{
		this.Application.Application.FileExporting -= new EventHandler<Autodesk.Revit.DB.Events.FileExportingEventArgs>(CENTRALPATH_TO_CentralSTRG);
		this.Application.Application.DocumentPrinting -= new EventHandler<Autodesk.Revit.DB.Events.DocumentPrintingEventArgs>(CENTRALPATH_TO_CentralSTRG);
		}
				#region Revit Macros generated code
		private void InternalStartup()
		{
			this.Startup += new System.EventHandler(Module_Startup);
			this.Shutdown += new System.EventHandler(Module_Shutdown);
		}
		#endregion
		internal void CENTRALPATH_TO_CentralSTRG(object sender, FileExportingEventArgs args, DocumentPrintedEventArgs args2)
					
				{
        	UIDocument uidoc = this;  
        	View view = uidoc.ActiveView;
        	
        	
    		// collect the titleblock and the parameter extract central path  
    		var ModelPath = uidoc.Document.GetWorksharingCentralModelPath();
    		string CentralServerPath = ModelPathUtils.ConvertModelPathToUserVisiblePath(ModelPath);
        	string titleBlockFamilyTypeName = "D 22 x 34 Horizontal";  
        	
  
        	FamilyInstance titleBlock = new FilteredElementCollector(uidoc.Document, view.Id)  
            	.OfCategory(BuiltInCategory.OST_TitleBlocks)  
            	.OfClass(typeof(FamilyInstance))  
            	.Cast<FamilyInstance>()  
            	.Where(f => f.Name == titleBlockFamilyTypeName)  
            	.FirstOrDefault();
        	
        	//collect and set parameter.
			FilteredElementCollector collector = new FilteredElementCollector(uidoc.Document)
				.OfClass(typeof(ViewSheet))
				.WhereElementIsNotElementType();
			foreach(Element e in collector)
			{
				
				Parameter Param = e.LookupParameter("CentralLocation");
				if (Param !=null)
				{
			//Start transaction
					using (Transaction t = new Transaction(uidoc.Document,"Place family Instance"))
					{
						t.Start();
			//SetParameter
						Param.Set(CentralServerPath);

						t.Commit();
					}
				}
			}}

	}
}

 

 

 

0 Likes
Message 8 of 10

sragan
Collaborator
Collaborator

The GUID is actually in the shared parameter file.  (Shared parameter files are text files, and you can open and look at them in a text editor, although that isn't the best way to view or edit shared parameters.)

 

So as long as you keep using the same shared parameter file, the GUID will not change.

 

Message 9 of 10

sragan
Collaborator
Collaborator

@davidsUUGCH wrote:

 

 

I have a questions in line 46 on the code you provided i see this:

Document.PathName

So i gather if the project is A360 will this be filled or will it give an error? I was told not to worry about A360 since it has its own management protocols too see who prints what we don't need to implement this control.

 


Try it and find out.   I often add taskdialog boxes, or message boxes:


.....Document.Pathname....

Taskdialog.Show("File Path", Document.Pathname.ToString());

 

If it gives an error, you can wrap it in a try-catch block, and then just exit silently since you don't care if the add in runs if its a A360 document.

 

Try

{

...Document.Pathname.....

 

...the rest of your code

}

Catch

{

//exit the program if there is an error

}

 

Message 10 of 10

RPTHOMAS108
Mentor
Mentor

There are API methods for finding out if the model is cloud based such as:

Document.IsModelInCloud
ModelPath.CloudPath
ModelPath.Region

 

The point of the shared parameter GUID is that it doesn't change. I don't know what other people are referring to perhaps they wonder why the same named parameter in two different projects is not treated as the same (the GUID distinguishes it so is what counts and doesn't change).