I have a few external commands that work perfectly when called by a pulldown button in Revit. I was attempting to upgrade the code by creating a list of commands in a WPF window using the MVVM pattern - mostly. There are no models in these cases instead a service that speaks to the Revit file. Below is an example of a service executes a call to remove materials:
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
namespace DevTools.Services.Cleaner
{
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
[Journaling(JournalingMode.NoCommandData)]
public class PurgeAllMaterialsService : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
var uiDoc = commandData.Application.ActiveUIDocument;
var doc = uiDoc.Document;
try
{
using Transaction trans = new(doc, "Delete all materials");
var allMaterials = new FilteredElementCollector(doc)
.OfClass(typeof(Material))
.ToElementIds();
var count = 0;
trans.Start();
foreach (var id in allMaterials)
{
try
{
var m = doc.GetElement(id) as Material;
{
uiDoc.Document.Delete(id);
count++;
}
}
catch (Exception ex)
{
message = ex.Message;
return Result.Failed;
}
}
trans.Commit();
TaskDialog.Show("Delete All Materials", count + " materials have been deleted");
return Result.Succeeded;
}
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
{
return Result.Cancelled;
}
catch (Exception ex)
{
message = ex.Message;
return Result.Failed;
}
}
}
}
The view-model calls the service in a relay command
using CommunityToolkit.Mvvm.Input;
using DevTools.Services.Cleaner;
namespace DevTools.ViewModels
{
public partial class CleanerViewModel
{
private PurgeAllMaterialsService _purgeAllMaterialsService;
[RelayCommand]
private void PurgeAllMaterials()
{
_purgeAllMaterialsService = new PurgeAllMaterialsService();
}
}
}
and the command passes the service to the view.
using Autodesk.Revit.Attributes;
using DevTools.Services.Cleaner;
using DevTools.ViewModels;
using DevTools.Views;
using Nice3point.Revit.Toolkit.External;
namespace DevTools.Commands
{
[UsedImplicitly]
[Transaction(TransactionMode.Manual)]
public class CleanWindowCommand : ExternalCommand
{
public override void Execute()
{
var viewModel = new CleanerViewModel();
var view = new CleanerPage(viewModel);
view.ShowDialog();
}
}
}
in the view the command is called by a button like so.
<Button Content="Purge Materials"
Command="{Binding PurgeAllMaterialsCommand, Mode=OneWay}"
Width="200"
Height="28"
Margin="0,10,0,0"
BorderBrush="Transparent"
Background="{StaticResource HeaderBackgroundBrush}"
Foreground="{StaticResource LightBrush}" />
The problem is the button does not execute the command. What is missing? Is the WPF window blocking the command bein sent?