Hey, sorry for late reply. I've been very busy.
It's a listing tool although it's quite easy to also use it to modify document by correctly using transactions. You could just simply start and commit transaction on top of Execute method in IExternalEventHandler class or if you pass document as argument to your delete method then why you just not start and commit transaction outside the loop. I improved the example and added Delete walls option with cancelation and TaskDialog to choose if you want to roll back changes.
Current Execute method in IExternalEventHandler class:
public void Execute(UIApplication app)
{
try
{
DataViewModel viewModel = ThisDocument.Instance.ViewModel;
if(viewModel.Action == ActionType.GetWalls)
{
viewModel.DataModel.GetWallModels(app.ActiveUIDocument.Document);
}
if(viewModel.Action == ActionType.DeleteWalls)
{
viewModel.DataModel.DeleteWallModels(app.ActiveUIDocument.Document);
}
}
catch (Exception ex)
{
TaskDialog.Show("Error", ex.ToString());
}
}
DeleteWalls method in DataModel class:
public void DeleteWallModels(Document doc)
{
List<Wall> walls = new FilteredElementCollector(doc).OfClass(typeof(Wall)).Select(e => e as Wall).ToList();
int counter = 0;
int totalItems = walls.Count;
WallModels = new List<WallModelItem>();
using (TransactionGroup tgroup = new TransactionGroup(doc, "Delete all walls"))
{
tgroup.Start();
foreach (Wall w in walls)
{
using (Transaction tx = new Transaction(doc, "Delete wall"))
{
counter++;
WallModelItem deletedWall = WallModelItem.Initialize(w);
WallModels.Add(deletedWall);
tx.Start();
doc.Delete(w.Id);
tx.Commit();
double percentage = ((double)counter / (double)totalItems) * 100;
Worker.ReportProgress((int)percentage, string.Format("Deleted {0} of {1}", counter, totalItems));
if(IsCancelled)
{
var result = TaskDialog.Show("Info", "Would you like to roll back all changes?", TaskDialogCommonButtons.Yes | TaskDialogCommonButtons.No);
if(result == TaskDialogResult.Yes)
{
Worker.ReportProgress((int)percentage, string.Format("Canceled, rolled back, deleted 0 of {0}", totalItems));
WallModels.Clear();
tgroup.RollBack();
}
else
{
Worker.ReportProgress((int)percentage, string.Format("Canceled, deleted {0} of {1}", counter, totalItems));
tgroup.Assimilate();
}
SignalEvent.Set();
return;
}
}
}
tgroup.Assimilate();
}
Worker.ReportProgress(100, "Finished!");
SignalEvent.Set();
}
Full solution you can check in attached document macro.
EDIT: Please also focus on using IExternalEventHandler correctly. Proper way is to Raise() the event so Revit will "find" related object and call Execute(UIApplication app) method. This way you can process document changes inside valid data context.
Best regards
Marek