Yep, I'm using failure processing event.
I am doing multiple things but let's focus only on the problem:
The goal is this - When the user tries to delete a part (That was created in the past by my code and has a scheme I made), raise a popup saying he can't do that and block the deletion. I am doing that successfully!
In addition to blocking the deletion, I don't want the error message I attached yesterday to be shown, so there won't be a confusion.
To block the deletion I have a class which inherits from IUpdater and uses a FailureDefinition GUID that I registered when Revit loads:
public class SplitElementUpdater : IUpdater
{
static AddInId m_appId;
static UpdaterId m_updaterId;
/// <summary>
/// Finds the failure definition id based on a constant GUID
/// </summary>
/// <returns></returns>
private static FailureDefinitionId GetFailureDefinitionId()
{
FailureDefinitionRegistry failureDefinitionRegistry = Autodesk.Revit.ApplicationServices.Application.GetFailureDefinitionRegistry();
FailureDefinitionId FailureDefinitionId = new FailureDefinitionId(FailureDefinitionIdGuid.Value);
return failureDefinitionRegistry.FindFailureDefinition(FailureDefinitionId).GetId();
}
public FailureDefinitionId _failureId = GetFailureDefinitionId();
// constructor takes the AddInId for the add-in associated with this updater
public SplitElementUpdater(AddInId id)
{
m_appId = id;
m_updaterId = new UpdaterId(m_appId, Guid.NewGuid());
}
public void Execute(UpdaterData data)
{
try
{
Document doc = data.GetDocument();
ICollection<ElementId> changedElements = data.GetModifiedElementIds().Concat(data.GetDeletedElementIds()).ToList();
DialogResult userResult = MessageBox.Show(
"You are trying to edit a part which was divided by an automation tool. To edit this part, first revert the division, then edit the part normally. Do you wish to open the “Surface Split” tool?",
"", MessageBoxButtons.OKCancel);
if (userResult.Equals(DialogResult.OK))
{
RevitDBUtils.InitializeStaticUtils(doc, RevitDBUtils.uidoc, RevitDBUtils.uiapp, RevitDBUtils.dllFolder, eDiscipline.Architectural);
RevitDBUtils.ExecuteMethodInEvent(() =>
{
SurfaceSplitTabsWindow window = new SurfaceSplitTabsWindow(1);
window.Show();
}, "Open Revert Surface Split window");
}
// Create a failure message that will cancel the operation
FailureMessage failureMessage = new FailureMessage(_failureId);
failureMessage.SetFailingElements(changedElements);
doc.PostFailure(failureMessage);
}
catch
{
}
}
public string GetAdditionalInformation()
{
return "Surface Split Updater for preventing modifying elements divided by Surface Split";
}
public ChangePriority GetChangePriority()
{
return ChangePriority.FreeStandingComponents;
}
public UpdaterId GetUpdaterId()
{
return m_updaterId;
}
public string GetUpdaterName()
{
return "Surface Split Updater";
}
}
This class works as expected and blocks the deletion, I'm setting up the trigger here:
public static UpdaterId SurfaceSplitElementUpdaterSetup(AddInId addinId, Document doc)
{
SplitElementUpdater splitUpdater = new SplitElementUpdater(addinId);//Create a surface split updater for alerting on modified divided elements
UpdaterRegistry.RegisterUpdater(splitUpdater);//register the updater
UpdaterRegistered = true;
// Creating filters for the updater:
ElementMulticategoryFilter catFilter = new ElementMulticategoryFilter(new List<BuiltInCategory> { BuiltInCategory.OST_Parts });//Create categories filter
ExtensibleStorageFilter extensibleStorageFilter = new ExtensibleStorageFilter(SplitFlag.GetGuid());
//Create extensible storage filter of elements with the Surface split Element Info Guid
LogicalAndFilter bothFilters = new LogicalAndFilter(catFilter, extensibleStorageFilter);//combine both filters to a single filter
ChangeType elementDeletion = Element.GetChangeTypeElementDeletion();//the change type of an element deletion
ChangeType geometryChange = Element.GetChangeTypeGeometry();//the change type of a geometry change
UpdaterId updaterId = splitUpdater.GetUpdaterId();
//We want to trigger when changing some of the params:
List<Parameter> parameters = new List<Parameter>();
parameters.Add(GetPanelIDUtils.GetPanelIdParameter(doc));
parameters.Add(GetFromDocUtils.GetParameter(ParametersConstants.FACTORY, doc));
parameters.Add(GetFromDocUtils.GetParameter(ParametersConstants.MATERIAL, doc));
parameters.Add(GetFromDocUtils.GetParameter(BuiltInParameter.ROOF_BASE_LEVEL_PARAM, doc));
foreach (Parameter parameter in parameters)
{
if (parameter != null)
{
ChangeType paramChange = Element.GetChangeTypeParameter(parameter);
UpdaterRegistry.AddTrigger(updaterId, bothFilters, paramChange);
}
}
// add the triggers for the updater
UpdaterRegistry.AddTrigger(updaterId, bothFilters, elementDeletion);
UpdaterRegistry.AddTrigger(updaterId, bothFilters, geometryChange);
return splitUpdater.GetUpdaterId();
}
All of this is fine!
And now, the problem 🙂
We know we can't swallow the error because it's of 'error' severity, but I'm unable to resolve it as well (Tried with / without resolve failure, tried proceed with commit and continue, nothing worked)
public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor)
{
IList<FailureMessageAccessor> failList = new List<FailureMessageAccessor>();
failList = failuresAccessor.GetFailureMessages(); // Inside event handler, get all warnings
foreach (FailureMessageAccessor failure in failList)
{
FailureDefinitionId failID = failure.GetFailureDefinitionId();
if (failID == BuiltInFailures.DPartFailures.DeletingDPartWillDeleteMorePartsError)
{
failure.SetCurrentResolutionType(FailureResolutionType.Default);
failuresAccessor.GetFailureHandlingOptions().SetClearAfterRollback(true);
//failuresAccessor.ResolveFailure(failure);
TransactionStatus a = failuresAccessor.RollBackPendingTransaction();
return FailureProcessingResult.ProceedWithRollBack;
}
}
return FailureProcessingResult.Continue;
}
Thank you!