The UIApplication class provides five events for programs to listen to. They are DialogBoxShowing, ApplicationClosing, Idling, ViewActivated, and ViewActivating.
In this article, we will demonstrate these events in detail with some use cases.
Let’s look at the DialogBoxShowing event first:
public static void UIAppEvent_DialogBoxShowing_Handler(Object sender, EventArgs args)
{
Autodesk.Revit.ApplicationServices.Application app = sender as Autodesk.Revit.ApplicationServices.Application;
UIApplication uiApp = new UIApplication(app);
DialogBoxShowingEventArgs specArgs = args as 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) // The Materials dialog
{
if( specArgs.Cancellable )
{
specArgs.Cancel = true;
}
specArgs.OverrideResult(2); // Just give the result 2 a try!
MessageBox.Show("The result of the DialogBox 1176 (Materials) will be overridden as 2!", "UIApplication Event Test by Spiderinnet"); // Not use TaskDialog to avoid recursive loop!
}
}
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 can construct one from the Application. 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 static void UIAppEvent_ApplicationClosing_Handler(Object sender, EventArgs args)
{
Autodesk.Revit.ApplicationServices.ControlledApplication app = sender as Autodesk.Revit.ApplicationServices.ControlledApplication;
ApplicationClosingEventArgs specArgs = args as ApplicationClosingEventArgs;
if (app.Product== ProductType.Architecture)
{
if (specArgs.Cancellable)
{
specArgs.Cancel = true;
TaskDialog td = new TaskDialog("UIApplication Event Test by Spiderinnet");
td.Id = "10001";
td.MainInstruction = "The ApplicationClosing event will be cancelled!";
td.Show();
}
}
}
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 static void UIAppEvent_Idling_Handler(Object sender, EventArgs args)
{
Autodesk.Revit.ApplicationServices.Application app = sender as Autodesk.Revit.ApplicationServices.Application;
UIApplication uiApp = new UIApplication(app);
IdlingEventArgs specArgs = args as IdlingEventArgs;
TaskDialog td = 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();
uiApp.Idling -= UIAppEvent_Idling_Handler;
}
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 want the UIAppliccation, we can construct one from the Application as demonstrated.
Now, the two view relevant events also deserve a look:
public static void UIAppEvent_ViewActivated_Handler(Object sender, EventArgs args)
{
Autodesk.Revit.ApplicationServices.Application app = sender as Autodesk.Revit.ApplicationServices.Application;
UIApplication uiApp = new UIApplication(app);
ViewActivatedEventArgs specArgs = args as ViewActivatedEventArgs;
TaskDialog td = 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();
}
public static void UIAppEvent_ViewActivating_Handler(Object sender, EventArgs args)
{
Autodesk.Revit.ApplicationServices.Application app = sender as Autodesk.Revit.ApplicationServices.Application;
UIApplication uiApp = new UIApplication(app);
ViewActivatingEventArgs specArgs = args as ViewActivatingEventArgs;
TaskDialog td = 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();
}
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.
The whole UIApplication event handlers, the registration and un-registration code of all the UIApplication events have been appended below for reference:
UIApplication event handlers:
using System;
using System.Text;
using System.Xml;
using System.Linq;
using System.Reflection;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Forms;
using System.IO;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Events;
using Autodesk.Revit.DB.Architecture;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.UI.Events;
using Autodesk.Revit.Collections;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.Utility;
using RvtApplication = Autodesk.Revit.ApplicationServices.Application;
using RvtDocument = Autodesk.Revit.DB.Document;
namespace RevitAddinCS1
{
public class UIAppEventHandlers1
{
public static void UIAppEvent_ApplicationClosing_Handler(Object sender, EventArgs args)
{
Autodesk.Revit.ApplicationServices.ControlledApplication app = sender as Autodesk.Revit.ApplicationServices.ControlledApplication;
ApplicationClosingEventArgs specArgs = args as ApplicationClosingEventArgs;
if (app.Product== ProductType.Architecture)
{
if (specArgs.Cancellable)
{
specArgs.Cancel = true;
TaskDialog td = new TaskDialog("UIApplication Event Test by Spiderinnet");
td.Id = "10001";
td.MainInstruction = "The ApplicationClosing event will be cancelled!";
td.Show();
}
}
}
public static void UIAppEvent_DialogBoxShowing_Handler(Object sender, EventArgs args)
{
Autodesk.Revit.ApplicationServices.Application app = sender as Autodesk.Revit.ApplicationServices.Application;
UIApplication uiApp = new UIApplication(app);
DialogBoxShowingEventArgs specArgs = args as 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) // The Materials dialog
{
if( specArgs.Cancellable )
{
specArgs.Cancel = true;
}
specArgs.OverrideResult(2); // Just give the result 2 a try!
MessageBox.Show("The result of the DialogBox 1176 (Materials) will be overridden as 2!", "UIApplication Event Test by Spiderinnet"); // Not use TaskDialog to avoid recursive loop!
}
}
public static void UIAppEvent_Idling_Handler(Object sender, EventArgs args)
{
Autodesk.Revit.ApplicationServices.Application app = sender as Autodesk.Revit.ApplicationServices.Application;
UIApplication uiApp = new UIApplication(app);
IdlingEventArgs specArgs = args as IdlingEventArgs;
TaskDialog td = 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();
uiApp.Idling -= UIAppEvent_Idling_Handler;
}
public static void UIAppEvent_ViewActivated_Handler(Object sender, EventArgs args)
{
Autodesk.Revit.ApplicationServices.Application app = sender as Autodesk.Revit.ApplicationServices.Application;
UIApplication uiApp = new UIApplication(app);
ViewActivatedEventArgs specArgs = args as ViewActivatedEventArgs;
TaskDialog td = 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();
}
public static void UIAppEvent_ViewActivating_Handler(Object sender, EventArgs args)
{
Autodesk.Revit.ApplicationServices.Application app = sender as Autodesk.Revit.ApplicationServices.Application;
UIApplication uiApp = new UIApplication(app);
ViewActivatingEventArgs specArgs = args as ViewActivatingEventArgs;
TaskDialog td = 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();
}
}
}
UIApplication event registration in the OnStartup implementation of an IExternalApplication interface:
public Result OnStartup(UIControlledApplication uiApp)
{
try
{
//……
uiApp.ApplicationClosing += UIAppEventHandlers1.UIAppEvent_ApplicationClosing_Handler;
uiApp.DialogBoxShowing += UIAppEventHandlers1.UIAppEvent_DialogBoxShowing_Handler;
uiApp.Idling += UIAppEventHandlers1.UIAppEvent_Idling_Handler;
uiApp.ViewActivated += UIAppEventHandlers1.UIAppEvent_ViewActivated_Handler;
uiApp.ViewActivating += UIAppEventHandlers1.UIAppEvent_ViewActivating_Handler;
return Result.Succeeded;
}
catch (Exception ex)
{
MessageBox.Show( ex.ToString() );
return Result.Failed;
}
}
UIApplication event un-registration in the OnShutdown implementation of the same IExternalApplication interface:
public Result OnShutdown(UIControlledApplication uiApp)
{
try
{
//……
uiApp.ApplicationClosing -= UIAppEventHandlers1.UIAppEvent_ApplicationClosing_Handler;
uiApp.DialogBoxShowing -= UIAppEventHandlers1.UIAppEvent_DialogBoxShowing_Handler;
uiApp.Idling -= UIAppEventHandlers1.UIAppEvent_Idling_Handler;
uiApp.ViewActivated -= UIAppEventHandlers1.UIAppEvent_ViewActivated_Handler;
uiApp.ViewActivating -= UIAppEventHandlers1.UIAppEvent_ViewActivating_Handler;
return Result.Succeeded;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
return Result.Failed;
}
}
RevitAddinWizard was used to create the prototype of the UIApplication event handlers we discussed here, their registration code and un-registration code automatically in a second.
Recent Comments