The UIApplication class provides five events for programs to listen to. They are DialogBoxShowing, ApplicationClosing, Idling, ViewActivated, and ViewActivating.
Revit Parameter Organizer can organize various Revit parameters such as Shared Parameters, Family Parameters, Project Parameters and Built-in Parameter in many good ways.
In this article, we will demonstrate these events in detail with some use cases in VB.NET.
Let’s look at the DialogBoxShowing event first:
Public Shared Sub UIAppEvent_DialogBoxShowing_Handler(ByVal sender As Object, ByVal args As EventArgs)
Dim app As Autodesk.Revit.ApplicationServices.Application = TryCast(sender, Autodesk.Revit.ApplicationServices.Application)
Dim uiApp As New UIApplication(app)
Dim specArgs As Autodesk.Revit.UI.Events.DialogBoxShowingEventArgs = TryCast(args, Autodesk.Revit.UI.Events.DialogBoxShowingEventArgs)
'TaskDialog.Show("UIApplication Event Test by Spiderinnet", string.Format("HelpId: {0}", specArgs.HelpId)); // Recursive loop would occur!
MessageBox.Show(String.Format("HelpId: {0}", specArgs.HelpId), "UIApplication Event Test by Spiderinnet")
If specArgs.HelpId = 1176 Then
' The Materials dialog
If specArgs.Cancellable Then
specArgs.Cancel = True
End If
specArgs.OverrideResult(2)
' Just give the result 2 a try!
' Not use TaskDialog to avoid recursive loop!
MessageBox.Show("The result of the DialogBox 1176 (Materials) will be overridden as 2!", "UIApplication Event Test by Spiderinnet")
End If
End Sub
The DialogBoxShowing notification is supposed to be sent when any dialog boxes are going to show up. Its sender object is a Revit Application, not a UIApplication that people may expect, so if we want the UIApplication we have to construct one from the Application as demonstrated. The EventArgs argument is DialogBoxShowingEventArgs as expected. It has a HelpId property which can be used to identify which dialog box it is.
But things are not that simple. The first is that how we can know which dialog box has which HelpId. Unfortunately we have to sort it out by ourselves one by one. That is exactly what the first MessageBox in the event handler is going to assist us. It’s found that the Materials dialog has a HelpId of 1176.
The second is that not every dialog box has a good HelpId, or even can be monitored by the DialogBoxShowing event.
All these DialogBox, HelpId, DialogBoxShowing Event stuffs and much more have been addressed in another article in more detail:
TaskDialog vs DialogBox, Id vs HelpId, and DialogBoxShowing Event
The third is that dialog boxes cannot be canceled directly through setting the Cancel property of the DialogBoxShowingEventArgs argument because its Cancellable property seems to always return false!
The fourth is what the OverrideResult really be. Once again, we have to make some guess and do some experiments. We use 2 here and find out that this result flag seems to dismiss the dialog, or more accurately cancel the dialog right after it pops up.
Now let’s look at the ApplicationClosing event.
Public Shared Sub UIAppEvent_ApplicationClosing_Handler(ByVal sender As Object, ByVal args As EventArgs)
Dim app As Autodesk.Revit.ApplicationServices.ControlledApplication = TryCast(sender, Autodesk.Revit.ApplicationServices.ControlledApplication)
Dim specArgs As Autodesk.Revit.UI.Events.ApplicationClosingEventArgs = TryCast(args, Autodesk.Revit.UI.Events.ApplicationClosingEventArgs)
If app.Product = ProductType.Architecture Then
If specArgs.Cancellable Then
specArgs.Cancel = True
Dim td As New TaskDialog("UIApplication Event Test by Spiderinnet")
td.Id = "10001"
td.MainInstruction = "The ApplicationClosing event will be cancelled!"
td.Show()
End If
End If
End Sub
This time, the notification sender object is of type ControlledApplication which might be out of expectations of most people. The EventArgs argument is of type ApplicationClosingEventArgs as expected. However, the Cancellable property of the ApplicationClosingEventArgs is still always false, so the Cancel property doe not really make sense.
Now, it’s the turn of the Idling event:
Public Shared Sub UIAppEvent_Idling_Handler(ByVal sender As Object, ByVal args As EventArgs)
Dim app As Autodesk.Revit.ApplicationServices.Application = TryCast(sender, Autodesk.Revit.ApplicationServices.Application)
Dim uiApp As New UIApplication(app)
Dim specArgs As Autodesk.Revit.UI.Events.IdlingEventArgs = TryCast(args, Autodesk.Revit.UI.Events.IdlingEventArgs)
Dim td As New TaskDialog("UIApplication Event Test by Spiderinnet")
td.Id = "10002"
td.MainInstruction = "Idling event occured. The Idling event listener will be unregistered to avoid endless notifications!"
td.Show()
RemoveHandler uiApp.Idling, AddressOf UIAppEvent_Idling_Handler
End Sub
This event is very important and can help fufill some impossible missions if without it. For example, if something is not simple enough to be wrapped into a single transaction, we can resort to the Idling event. It is not possible to corver this complex topic in a sentence or two here. We will address it in more detail in the future in another post if necessary.
In the Idling event handler here, we only show some information and remove the handler from the system at the end. It is always a good idea to do so as when Revit reallly enters the idling state, the notification will be sent continuously and the performance will become an issue. If the Idling status needs to be got again, please just listen to the notification again and again remove it right after things are done. That will not only improve the performance but also save some confusing and non-structural global flags as well.
By the way, the notification sender object is of type Application again. It makes sense though since it’s unlikely that the ControlledApplication or the UIApplication will ever goes idling. If we really want the UIAppliccation, we can construct one from the Application as demonstrated.
Now, the two view relevant events also deserve a look:
Public Shared Sub UIAppEvent_ViewActivated_Handler(ByVal sender As Object, ByVal args As EventArgs)
Dim app As Autodesk.Revit.ApplicationServices.Application = TryCast(sender, Autodesk.Revit.ApplicationServices.Application)
Dim uiApp As New UIApplication(app)
Dim specArgs As Autodesk.Revit.UI.Events.ViewActivatedEventArgs = TryCast(args, Autodesk.Revit.UI.Events.ViewActivatedEventArgs)
Dim td As New TaskDialog("UIApplication Event Test by Spiderinnet")
td.Id = "10003"
td.MainInstruction = String.Format("The ActiveView has been changed from {0} to {1} with Status {2}.", specArgs.PreviousActiveView.Name, specArgs.CurrentActiveView.Name, specArgs.Status)
td.Show()
End Sub
Public Shared Sub UIAppEvent_ViewActivating_Handler(ByVal sender As Object, ByVal args As EventArgs)
Dim app As Autodesk.Revit.ApplicationServices.Application = TryCast(sender, Autodesk.Revit.ApplicationServices.Application)
Dim uiApp As New UIApplication(app)
Dim specArgs As Autodesk.Revit.UI.Events.ViewActivatingEventArgs = TryCast(args, Autodesk.Revit.UI.Events.ViewActivatingEventArgs)
Dim td As New TaskDialog("UIApplication Event Test by Spiderinnet")
td.Id = "10004"
td.MainInstruction = String.Format("The ActiveView is going to be changed from {0} to {1}.", specArgs.CurrentActiveView.Name, specArgs.NewActiveView.Name)
td.Show()
End Sub
They will be sent before and after a view is activated respectively. Of course, this means actually a view is switched from one to another, or the active view is changed. All these information can be got from the PreviousActiveView, CurrentActiveView, and the NewActiveView as demonstrated.
Once again, the notification sender object is of type Application. UIApplication type may make more sense here as far as view activation is concerned, but anyway it is not so big a deal since we can find (not create or new) one from the other.
Revit Family Organizer can organize various Revit family forms such as Family Files (.RFA), Opened Families, Loaded Families, Project Families, System Families, Nested Families, Family Types, and Family Materials in many different and good ways.
The whole UIApplication event handlers, the registration and un-registration code of all the UIApplication events in VB.NET have been appended below for reference:
UIApplication event handlers:
Imports System.Text
Imports System.Xml
Imports System.Linq
Imports System.Reflection
Imports System.ComponentModel
Imports System.Collections
Imports System.Collections.Generic
Imports System.Windows
Imports System.Windows.Media.Imaging
Imports System.Windows.Forms
Imports System.IO
Imports Autodesk.Revit.ApplicationServices
Imports Autodesk.Revit.Attributes
Imports Autodesk.Revit.DB
Imports Autodesk.Revit.DB.Events
Imports Autodesk.Revit.DB.Architecture
Imports Autodesk.Revit.DB.Structure
Imports Autodesk.Revit.DB.Mechanical
Imports Autodesk.Revit.DB.Electrical
Imports Autodesk.Revit.DB.Plumbing
Imports Autodesk.Revit.UI
Imports Autodesk.Revit.UI.Selection
Imports Autodesk.Revit.UI.Events
Imports Autodesk.Revit.Collections
Imports Autodesk.Revit.Exceptions
Imports Autodesk.Revit.Utility
Imports RvtApplication = Autodesk.Revit.ApplicationServices.Application
Imports RvtDocument = Autodesk.Revit.DB.Document
Public Class UIAppEventHandlers1
Public Shared Sub UIAppEvent_ApplicationClosing_Handler(ByVal sender As Object, ByVal args As EventArgs)
Dim app As Autodesk.Revit.ApplicationServices.ControlledApplication = TryCast(sender, Autodesk.Revit.ApplicationServices.ControlledApplication)
Dim specArgs As Autodesk.Revit.UI.Events.ApplicationClosingEventArgs = TryCast(args, Autodesk.Revit.UI.Events.ApplicationClosingEventArgs)
If app.Product = ProductType.Architecture Then
If specArgs.Cancellable Then
specArgs.Cancel = True
Dim td As New TaskDialog("UIApplication Event Test by Spiderinnet")
td.Id = "10001"
td.MainInstruction = "The ApplicationClosing event will be cancelled!"
td.Show()
End If
End If
End Sub
Public Shared Sub UIAppEvent_DialogBoxShowing_Handler(ByVal sender As Object, ByVal args As EventArgs)
Dim app As Autodesk.Revit.ApplicationServices.Application = TryCast(sender, Autodesk.Revit.ApplicationServices.Application)
Dim uiApp As New UIApplication(app)
Dim specArgs As Autodesk.Revit.UI.Events.DialogBoxShowingEventArgs = TryCast(args, Autodesk.Revit.UI.Events.DialogBoxShowingEventArgs)
'TaskDialog.Show("UIApplication Event Test by Spiderinnet", string.Format("HelpId: {0}", specArgs.HelpId)); // Recursive loop would occur!
MessageBox.Show(String.Format("HelpId: {0}", specArgs.HelpId), "UIApplication Event Test by Spiderinnet")
If specArgs.HelpId = 1176 Then
' The Materials dialog
If specArgs.Cancellable Then
specArgs.Cancel = True
End If
specArgs.OverrideResult(2)
' Just give the result 2 a try!
' Not use TaskDialog to avoid recursive loop!
MessageBox.Show("The result of the DialogBox 1176 (Materials) will be overridden as 2!", "UIApplication Event Test by Spiderinnet")
End If
End Sub
Public Shared Sub UIAppEvent_Idling_Handler(ByVal sender As Object, ByVal args As EventArgs)
Dim app As Autodesk.Revit.ApplicationServices.Application = TryCast(sender, Autodesk.Revit.ApplicationServices.Application)
Dim uiApp As New UIApplication(app)
Dim specArgs As Autodesk.Revit.UI.Events.IdlingEventArgs = TryCast(args, Autodesk.Revit.UI.Events.IdlingEventArgs)
Dim td As New TaskDialog("UIApplication Event Test by Spiderinnet")
td.Id = "10002"
td.MainInstruction = "Idling event occured. The Idling event listener will be unregistered to avoid endless notifications!"
td.Show()
RemoveHandler uiApp.Idling, AddressOf UIAppEvent_Idling_Handler
End Sub
Public Shared Sub UIAppEvent_ViewActivated_Handler(ByVal sender As Object, ByVal args As EventArgs)
Dim app As Autodesk.Revit.ApplicationServices.Application = TryCast(sender, Autodesk.Revit.ApplicationServices.Application)
Dim uiApp As New UIApplication(app)
Dim specArgs As Autodesk.Revit.UI.Events.ViewActivatedEventArgs = TryCast(args, Autodesk.Revit.UI.Events.ViewActivatedEventArgs)
Dim td As New TaskDialog("UIApplication Event Test by Spiderinnet")
td.Id = "10003"
td.MainInstruction = String.Format("The ActiveView has been changed from {0} to {1} with Status {2}.", specArgs.PreviousActiveView.Name, specArgs.CurrentActiveView.Name, specArgs.Status)
td.Show()
End Sub
Public Shared Sub UIAppEvent_ViewActivating_Handler(ByVal sender As Object, ByVal args As EventArgs)
Dim app As Autodesk.Revit.ApplicationServices.Application = TryCast(sender, Autodesk.Revit.ApplicationServices.Application)
Dim uiApp As New UIApplication(app)
Dim specArgs As Autodesk.Revit.UI.Events.ViewActivatingEventArgs = TryCast(args, Autodesk.Revit.UI.Events.ViewActivatingEventArgs)
Dim td As New TaskDialog("UIApplication Event Test by Spiderinnet")
td.Id = "10004"
td.MainInstruction = String.Format("The ActiveView is going to be changed from {0} to {1}.", specArgs.CurrentActiveView.Name, specArgs.NewActiveView.Name)
td.Show()
End Sub
End Class
UIApplication event registration in the OnStartup implementation of an IExternalApplication interface:
Public Function OnStartup(ByVal uiApp As UIControlledApplication) As Result Implements IExternalApplication.OnStartup
_cachedUiCtrApp = uiApp
Try
AddHandler uiApp.ApplicationClosing, AddressOf UIAppEventHandlers1.UIAppEvent_ApplicationClosing_Handler
AddHandler uiApp.DialogBoxShowing, AddressOf UIAppEventHandlers1.UIAppEvent_DialogBoxShowing_Handler
AddHandler uiApp.Idling, AddressOf UIAppEventHandlers1.UIAppEvent_Idling_Handler
AddHandler uiApp.ViewActivated, AddressOf UIAppEventHandlers1.UIAppEvent_ViewActivated_Handler
AddHandler uiApp.ViewActivating, AddressOf UIAppEventHandlers1.UIAppEvent_ViewActivating_Handler
Return Result.Succeeded
Catch ex As Exception
MessageBox.Show(ex.ToString())
Return Result.Failed
End Try
End Function
UIApplication event un-registration in the OnShutdown implementation of the same IExternalApplication interface:
Public Function OnShutdown(ByVal uiApp As UIControlledApplication) As Result Implements IExternalApplication.OnShutdown
Try
RemoveHandler uiApp.ApplicationClosing, AddressOf UIAppEventHandlers1.UIAppEvent_ApplicationClosing_Handler
RemoveHandler uiApp.DialogBoxShowing, AddressOf UIAppEventHandlers1.UIAppEvent_DialogBoxShowing_Handler
RemoveHandler uiApp.Idling, AddressOf UIAppEventHandlers1.UIAppEvent_Idling_Handler
RemoveHandler uiApp.ViewActivated, AddressOf UIAppEventHandlers1.UIAppEvent_ViewActivated_Handler
RemoveHandler uiApp.ViewActivating, AddressOf UIAppEventHandlers1.UIAppEvent_ViewActivating_Handler
Return Result.Succeeded
Catch ex As Exception
MessageBox.Show(ex.ToString())
Return Result.Failed
End Try
End Function
RevitAddinWizard was used to create the prototype of the UIApplication event handlers in VB.NET we discussed here, their registration code and un-registration code automatically in a second.
Recent Comments