#region Namespaces
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Events;
using Autodesk.Revit.UI;
using System;
using System.Collections.Generic;
#endregion
namespace Unconstrain_Dim_Delete
{
internal class App : IExternalApplication
{
public Result OnStartup(UIControlledApplication a)
{
a.ControlledApplication.ApplicationInitialized += ApplicationInitialized;
return Result.Succeeded;
}
private void ApplicationInitialized(object sender, ApplicationInitializedEventArgs e)
{
/*
* DOES NOT WORK BUT THAT IS THE GUID OF MY COMMAND....
*
* https://thebuildingcoder.typepad.com/blog/2013/10/programmatic-custom-add-in-external-command-launch.html
*
UIApplication uiapp = sender as UIApplication;
RevitCommandId cmdID = RevitCommandId.LookupCommandId("5d5ddf79-db55-49fb-83f1-0337a30c9ee0");
uiapp.PostCommand(cmdID);
*
*/
var command = new Command();
//I never remember if the sender is Application or UIApplication
if (sender is UIApplication)
command.Execute(sender as UIApplication);
else
command.Execute(new UIApplication(sender as Application));
}
public Result OnShutdown(UIControlledApplication a)
{
return Result.Succeeded;
}
} // END OF IE APP
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class Command : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
return Execute(commandData.Application);
}
public Result Execute(UIApplication a)
{
a.Application.FailuresProcessing += new EventHandler<FailuresProcessingEventArgs>(OnFailuresProcessing);
return Result.Succeeded;
}
private void OnFailuresProcessing(object sender,FailuresProcessingEventArgs e)
{
FailuresAccessor failuresAccessor = e.GetFailuresAccessor();
String transactionName = failuresAccessor.GetTransactionName();
IList<FailureMessageAccessor> fmas = failuresAccessor.GetFailureMessages();
if (fmas.Count == 0)
{
// FailureProcessingResult.Continue is to let the failure cycle continue next step.
e.SetProcessingResult(FailureProcessingResult.Continue);
return;
}
// If manually delete an element, the transaction name is 'Delete Selection' if the failure is caused by deleting element.
if (transactionName.Equals("Delete Selection"))
{
string keyWords = "A dimension that has EQ constraints is being deleted, but the elements will still be constrained.";
string fmaDescription = "";
foreach (FailureMessageAccessor fma in fmas)
{
fmaDescription = fma.GetDescriptionText();
failuresAccessor.ResolveFailure(fma);
}
if (fmaDescription.Contains(keyWords))
e.SetProcessingResult(FailureProcessingResult.ProceedWithCommit);
return;
}
e.SetProcessingResult(FailureProcessingResult.Continue);
}
} // END OF IE COMMAND
} // END OF NAMESPACE
So I got it to work, probably not the cleanest way. I couldn't figure out how to do this using just
IExternalApplication or IExternalCommand, so ended up using both and not registering the IExternalCommand in the .addin file... IExternalCommand has ExternalCommandData with the UIApplication and IExternalApplication allows starting code when Revit is initialized.
Also not sure what I was doing wrong, but I could not PostCommand() either... I had the external command registered in the .addin file and I followed this article:
Either way seems to work well, and I am curious if my coworkers notice any performance issues.
The definition of insanity is doing the same thing over and over again and expecting different results