### AsyncExternalEvent Example Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Demonstrates deleting all windows asynchronously. The delegate executes when Revit processes the event, and execution continues after completion. ```csharp private readonly AsyncExternalEvent _deleteWindowsAsyncEvent = new(application => { var document = application.ActiveUIDocument.Document; using var transaction = new Transaction(document, "Delete windows"); transaction.Start(); document.Delete(document.GetInstanceIds(BuiltInCategory.OST_Windows)); transaction.Commit(); //1. The delegate body executes when Revit processes the event }); private async Task DeleteWindowsAsync() { await _deleteWindowsAsyncEvent.RaiseAsync(); //2. Continues after the delegate has completed } ``` -------------------------------- ### Basic ExternalApplication Implementation Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Implement IExternalApplication to define startup and shutdown logic for a Revit add-in. This example shows how to create a ribbon panel and add a push button. ```csharp public class Application : ExternalApplication { public override void OnStartup() { var panel = Application.CreatePanel("Commands", "RevitAddin"); panel.AddPushButton("Execute") .SetImage("/RevitAddin;component/Resources/Icons/RibbonIcon16.png") .SetLargeImage("/RevitAddin;component/Resources/Icons/RibbonIcon32.png"); } public override void OnShutdown() { } } ``` -------------------------------- ### AsyncExternalEvent Example Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Shows how to delete a specific window asynchronously using a generic external event. The delegate receives an ElementId argument. ```csharp private readonly AsyncExternalEvent _deleteWindowAsyncEvent = new((application, elementId) => { var document = application.ActiveUIDocument.Document; using var transaction = new Transaction(document, "Delete window"); transaction.Start(); document.Delete(elementId); transaction.Commit(); //1. The delegate body executes with the provided argument }); private async Task DeleteWindowAsync(ElementId elementId) { await _deleteWindowAsyncEvent.RaiseAsync(elementId); //2. Continues after the delegate has completed } ``` -------------------------------- ### AsyncRequestExternalEvent Example Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Demonstrates counting windows asynchronously and returning the count. The returned Task completes with the result once Revit finishes executing the delegate. ```csharp private readonly AsyncRequestExternalEvent _countWindowsAsyncEvent = new(application => { var document = application.ActiveUIDocument.Document; var elementIds = document.GetInstanceIds(BuiltInCategory.OST_Windows); //1. The delegate body executes and returns a value return elementIds.Count; }); private async Task CountWindowsAsync() { var count = await _countWindowsAsyncEvent.RaiseAsync(); //2. Continues after the delegate has completed, with the result } ``` -------------------------------- ### Begin Assembly Resolve Scope with Specific Type Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Starts an assembly resolution scope for a specified type, useful for loading dependencies related to that type. ```csharp using (ResolveHelper.BeginAssemblyResolveScope(typeof(ViewModel))) { return new Window(); } ``` -------------------------------- ### Set Availability Controller for External Command Source: https://github.com/nice3point/revittoolkit/blob/main/Changelog.md Implement a custom availability controller for an ExternalCommand using the SetAvailabilityController method. This example shows how to use AvailableCommandController for permanent accessibility. ```C# panel.AddPushButton("Execute") .SetAvailabilityController(); ``` -------------------------------- ### AsyncRequestExternalEvent Example Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Shows deleting a specific window asynchronously and returning a boolean result. The delegate accepts an ElementId and returns a TResult. ```csharp private readonly AsyncRequestExternalEvent _deleteWindowRequestEvent = new((application, elementId) => { var document = application.ActiveUIDocument.Document; using var transaction = new Transaction(document, "Delete window"); transaction.Start(); document.Delete(elementId); transaction.Commit(); //1. The delegate body executes with the provided argument and returns a value return true; }); private async Task DeleteWindowAsync(ElementId elementId) { var result = await _deleteWindowRequestEvent.RaiseAsync(elementId); //2. Continues after the delegate has completed, with the result } ``` -------------------------------- ### Asynchronous ExternalApplication for I/O Operations Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Implement AsyncExternalApplication for asynchronous startup and shutdown, suitable for I/O-bound operations like network requests or file access. Ensures UI responsiveness during these operations. ```csharp public class Application : AsyncExternalApplication { public override async Task OnStartupAsync() { using var httpClient = new HttpClient(); var configuration = await httpClient.GetStringAsync("https://api.example.com/config"); var panel = Application.CreatePanel(configuration.PanelTitle); panel.AddPushButton(configuration.ButtonTitle); } public override async Task OnShutdownAsync() { await SaveSettingsAsync(); } } ``` -------------------------------- ### Initialize Selection Configuration Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Creates a default selection configuration that allows all elements for selection. ```csharp var selectionConfiguration = new SelectionConfiguration(); uiDocument.Selection.PickObject(ObjectType.Element, selectionConfiguration.Filter); ``` -------------------------------- ### Register Dockable Pane with UI Configuration Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Provides access to create a new dockable pane and configures its initial state and UI element. ```csharp DockablePaneProvider .Register(application, new Guid(), "Dockable pane") .SetConfiguration(data => { data.FrameworkElement = new RevitAddInView(); data.InitialState = new DockablePaneState { MinimumWidth = 300, MinimumHeight = 400, DockPosition = DockPosition.Right }; }); ``` -------------------------------- ### Register Dockable Pane with Framework Element Creator Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Registers a dockable pane and sets its Framework Element Creator. Can be initialized with or without a service provider. ```csharp DockablePaneProvider.Register(application, guid, title) .SetConfiguration(data => { data.FrameworkElementCreator = new FrameworkElementCreator(); data.FrameworkElementCreator = new FrameworkElementCreator(serviceProvider); }); ``` -------------------------------- ### Begin Assembly Resolve Scope with Directory Path Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Establishes an assembly resolution scope by specifying a directory path, allowing loading of assemblies from that location. ```csharp using (ResolveHelper.BeginAssemblyResolveScope(@"C:\Libraries")) { return LoadExternalLibrary(); } ``` -------------------------------- ### Specify Directory Path for Assembly Resolution Source: https://github.com/nice3point/revittoolkit/blob/main/Changelog.md New functionality allows specifying a directory path directly for assembly resolution, enabling more flexible loading of external libraries. ```csharp // Path-based (new) using (ResolveHelper.BeginAssemblyResolveScope(@"C:\Libraries")) { window.Show(); } // Nested scopes (new) - searches innermost first using (ResolveHelper.BeginAssemblyResolveScope(@"C:\Shared\Common")) using (ResolveHelper.BeginAssemblyResolveScope(@"C:\Plugin")) using (ResolveHelper.BeginAssemblyResolveScope()) { // Searches: MyType directory -> Plugin -> Common window.Show(); } ``` -------------------------------- ### Registering a Dockable Pane with Framework Element Creator Source: https://github.com/nice3point/revittoolkit/blob/main/Changelog.md Shows how to register a dockable pane provider for an application, specifying its ID, title, and a creator for its framework element. This is useful for creating custom UI elements within Revit. ```C# DockablePaneProvider.Register(application) .SetId(guid) .SetTitle(title) .SetConfiguration(data => { data.FrameworkElementCreator = new FrameworkElementCreator(); }); ``` -------------------------------- ### Begin Assembly Resolve Scope with Application Type Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Manages assembly resolution scope for a given application type, ensuring dependencies are correctly loaded within the scope. ```csharp using (ResolveHelper.BeginAssemblyResolveScopeСкопировать код) { window.Show(); } // Assembly resolution is restored automatically ``` -------------------------------- ### Using ResolveHelper for Dependency Resolution Source: https://github.com/nice3point/revittoolkit/blob/main/Changelog.md Illustrates the usage of ResolveHelper to manage assembly resolution for dependencies. It's recommended to use this within a try-finally block to ensure proper cleanup of the assembly resolve context. ```C# try { ResolveHelper.BeginAssemblyResolve(); window.Show(); } finally { ResolveHelper.EndAssemblyResolve(); } ``` -------------------------------- ### AsyncExternalCommand with HTTP Request Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Implement asynchronous Revit external commands using ExecuteAsync() for I/O-bound operations. The UI remains responsive during async tasks. ```csharp [Transaction(TransactionMode.Manual)] public class Command : AsyncExternalCommand { public override async Task ExecuteAsync() { using var httpClient = new HttpClient(); var response = await httpClient.GetStringAsync("https://example.com"); using var transaction = new Transaction(Application.ActiveUIDocument.Document, "Update Parameter"); transaction.Start(); var element = Application.ActiveUIDocument.Document.GetElement(id); element?.FindParameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS)?.Set(response); transaction.Commit(); } } ``` -------------------------------- ### Use ActiveDocument and ActiveUiDocument Source: https://github.com/nice3point/revittoolkit/blob/main/Changelog.md The Document and UiDocument properties are obsolete. Use _ActiveDocument and _ActiveUiDocument respectively for accessing the current Revit document and UI document. ```C# var doc = _ActiveDocument; var uiDoc = _ActiveUiDocument; ``` -------------------------------- ### Customize Selection Configuration for Elements and References Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Sets rules for both element and reference selection, allowing specific elements and disallowing all references. ```csharp var selectionConfiguration = new SelectionConfiguration() .Allow.Element(element => element.Category.Id.AreEquals(BuiltInCategory.OST_Walls)) .Allow.Reference((reference, xyz) => false); uiDocument.Selection.PickObject(ObjectType.Element, selectionConfiguration.Filter); ``` -------------------------------- ### Replace Dialog and Failure Suppression with Scopes Source: https://github.com/nice3point/revittoolkit/blob/main/Changelog.md Utilize disposable scopes like BeginDialogSuppressionScope() and BeginFailureSuppressionScope() for managing dialog and failure suppression, replacing manual try-finally blocks. ```csharp // Before try { Context.SuppressDialogs(); Context.SuppressFailures(); // operations } finally { Context.RestoreDialogs(); Context.RestoreFailures(); } // After (auto-fix available) using (RevitContext.BeginDialogSuppressionScope()) using (RevitApiContext.BeginFailureSuppressionScope()) { // operations } ``` -------------------------------- ### Nested Assembly Resolve Scopes Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Demonstrates nested assembly resolution scopes, where dependencies are searched from the innermost scope outwards. ```csharp using (ResolveHelper.BeginAssemblyResolveScope(@"C:\Shared\Common")) using (ResolveHelper.BeginAssemblyResolveScope(@"C:\Plugin")) { // First searches in Plugin, then in Common return new Window(); } ``` -------------------------------- ### External Event with Multiple Extra Parameters Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md For methods with two or more extra parameters, a sealed record bundles them, and extension methods simplify raising the event. ```csharp public partial class MyViewModel { private Room CreateRoom(UIApplication application, Level level, UV coordinate) { var document = application.ActiveUIDocument.Document; using var transaction = new Transaction(document, "Create room"); transaction.Start(); var createdRoom = document.Create.NewRoom(level, coordinate); transaction.Commit(); return createdRoom; } } ``` -------------------------------- ### External Event for void Methods without Parameters Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md For void methods without parameters, both sync and async event properties are generated. ```csharp [ExternalEvent] private void DeleteWindows() { _document.Delete(_windowIds); } ``` -------------------------------- ### Accessing Revit Context Properties Source: https://github.com/nice3point/revittoolkit/blob/main/Changelog.md Demonstrates how to access computed properties for retrieving Revit objects in the current session, including application, document, and view information. ```C# Context.Document.Create.NewFamilyInstance(); Context.ActiveView = view; ``` -------------------------------- ### Calling External Event with Individual Arguments Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Use the generated extension methods to call the async event with individual parameters, avoiding manual creation of the arguments record. ```csharp var room = await CreateRoomAsyncEvent.RaiseAsync(level, coordinate); ``` -------------------------------- ### ExternalDBApplication for UI-less Operations Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Implement ExternalDBApplication for operations that do not require UI access. It follows the same structure as ExternalApplication but is intended for background database tasks. ```csharp public class Application : ExternalDBApplication { public override void OnStartup() { } public override void OnShutdown() { } } ``` -------------------------------- ### Load Family with Custom Options Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Load families into the document using document.LoadFamily with custom FamilyLoadOptions. Options can be set to control behavior like overwriting existing families or specifying the family source. ```C# document.LoadFamily(fileName, new FamilyLoadOptions(), out var family); document.LoadFamily(fileName, new FamilyLoadOptions(false, FamilySource.Project), out var family); document.LoadFamily(fileName, UIDocument.GetRevitUIFamilyLoadOptions(), out var family); ``` -------------------------------- ### Check Revit API Mode Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Use RevitContext.IsRevitInApiMode to verify if the Revit API context is available, which is necessary for applications running in separate threads or using asynchronous API requests. ```C# public void Execute() { if (RevitContext.IsRevitInApiMode) { ModifyDocument(); } } ``` -------------------------------- ### Use Source Generator for External Events Source: https://github.com/nice3point/revittoolkit/blob/main/Changelog.md Leverage the [ExternalEvent] source generator to automatically create boilerplate code for external events, reducing manual implementation. ```csharp // After (source generator) partial class MyViewModel { [ExternalEvent] private void DeleteElement(UIApplication application) { application.ActiveUIDocument.Document.Delete(elementId); } } // Usage: DeleteElementEvent.Raise(); // or await DeleteElementAsyncEvent.RaiseAsync(); ``` -------------------------------- ### External Event with UIApplication Parameter Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md When a method accepts a UIApplication parameter, the generated events pass the application instance to the handler. ```csharp [ExternalEvent] private void DeleteWindows(UIApplication application) { var document = application.ActiveUIDocument.Document; using var transaction = new Transaction(document, "Delete windows"); transaction.Start(); document.Delete(document.GetInstanceIds(BuiltInCategory.OST_Windows)); transaction.Commit(); } ``` -------------------------------- ### ExternalCommand Implementation Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Override the Execute() method to implement a Revit external command. This base class handles dependency resolution automatically. ```csharp [Transaction(TransactionMode.Manual)] public class Command : ExternalCommand { public override void Execute() { var document = Application.ActiveUIDocument.Document; } } ``` -------------------------------- ### Replace Assembly Resolve with Scopes Source: https://github.com/nice3point/revittoolkit/blob/main/Changelog.md Replace BeginAssemblyResolve() and EndAssemblyResolve() with the BeginAssemblyResolveScope() method for managing assembly resolution contexts. ```csharp // Before try { ResolveHelper.BeginAssemblyResolve(); window.Show(); } finally { ResolveHelper.EndAssemblyResolve(); } // After (auto-fix available) using (ResolveHelper.BeginAssemblyResolveScope()) { window.Show(); } ``` -------------------------------- ### Replace Context with RevitContext or RevitApiContext Source: https://github.com/nice3point/revittoolkit/blob/main/Changelog.md Use RevitContext or RevitApiContext instead of the obsolete Context class for accessing Revit application and document information. ```csharp // Before Context.ActiveDocument.Delete(elementId); Context.Application.Username; // After (auto-fix available) RevitContext.ActiveDocument.Delete(elementId); RevitApiContext.Application.Username; ``` -------------------------------- ### External Event with Return Value and One Extra Parameter Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Methods with a return value and one extra parameter generate an async event property with typed arguments and return value. ```csharp [ExternalEvent] private int CountWindows(UIApplication application, BuiltInCategory category) { return application.ActiveUIDocument.Document.GetInstanceIds(category).Count; } ``` -------------------------------- ### Generated Record and Extension Methods for Multiple Parameters Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md The generator creates a sealed record for arguments and extension methods to call RaiseAsync with individual parameters. ```csharp public partial class MyViewModel { public IAsyncRequestExternalEvent CreateRoomAsyncEvent => field ??= new IAsyncRequestExternalEvent(CreateRoom); public sealed record CreateRoomArgs(Level Level, UV Coordinate); } public static partial class MyViewModelExtensions { public static Task RaiseAsync(this IAsyncRequestExternalEvent externalEvent, Level level, UV coordinate) { return externalEvent.RaiseAsync(new CreateRoomArgs(level, coordinate)); } } ``` -------------------------------- ### Replace Legacy ActionEventHandler with ExternalEvent Source: https://github.com/nice3point/revittoolkit/blob/main/Changelog.md Migrate from ActionEventHandler to ExternalEvent for handling Revit commands. The new approach simplifies event raising and execution. ```csharp // Before private readonly ActionEventHandler _handler = new(); private void Execute() { _handler.Raise(app => { app.ActiveUIDocument.Document.Delete(elementId); }); } // After private readonly ExternalEvent _handler = new(app => { app.ActiveUIDocument.Document.Delete(elementId); }); private void Execute() { _handler.Raise(); } ``` -------------------------------- ### Customize Selection Configuration for Elements Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Customizes the selection configuration to allow only specific elements based on a condition, such as category. ```csharp var selectionConfiguration = new SelectionConfiguration() .Allow.Element(element => element.Category.Id.AreEquals(BuiltInCategory.OST_Walls)); uiDocument.Selection.PickObject(ObjectType.Element, selectionConfiguration.Filter); ``` -------------------------------- ### Suppress Failures in Revit API Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Use RevitApiContext.BeginFailureSuppressionScope to automatically resolve all failures without user interruption. Pass false to cancel the transaction and undo failed changes. ```C# using (RevitApiContext.BeginFailureSuppressionScope()) { using var transaction = new Transaction(document, "Operation"); transaction.Start(); // Operations that may cause failures transaction.Commit(); } // Failure handling is restored automatically ``` ```C# using (RevitApiContext.BeginFailureSuppressionScope(resolveErrors: false)) { //User transactions ModifyDocument(); } ``` -------------------------------- ### Define External Event with ExternalEventAttribute Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Annotate a private method with [ExternalEvent] to automatically generate synchronous and asynchronous external event properties. ```csharp public partial class MyViewModel { [ExternalEvent] private void DeleteWindows(UIApplication application) { var document = application.ActiveUIDocument.Document; using var transaction = new Transaction(document, "Delete windows"); transaction.Start(); document.Delete(document.GetInstanceIds(BuiltInCategory.OST_Windows)); transaction.Commit(); } } ``` -------------------------------- ### External Event for Methods with Return Value Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md For methods that return a value, only an async event property is generated. ```csharp [ExternalEvent] private int CountWindows() { return _document.GetInstanceIds(BuiltInCategory.OST_Windows).Count; } ``` -------------------------------- ### External Event with One Extra Parameter Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md For methods with one additional parameter beyond UIApplication, typed event properties are generated. ```csharp [ExternalEvent] private void DeleteWindow(UIApplication application, ElementId elementId) { var document = application.ActiveUIDocument.Document; using var transaction = new Transaction(document, "Delete window"); transaction.Start(); document.Delete(elementId); transaction.Commit(); } ``` -------------------------------- ### Synchronous ExternalEvent for Revit API Interaction Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Use ExternalEvent to queue a delegate for execution within the Revit event queue. This ensures the operation runs when Revit is idle and ready, suitable for modeless window interactions. ```csharp private readonly ExternalEvent _deleteWindowsEvent = new(application => { var document = application.ActiveUIDocument.Document; using var transaction = new Transaction(document, "Delete windows"); transaction.Start(); document.Delete(document.GetInstanceIds(BuiltInCategory.OST_Windows)); transaction.Commit(); //2. The delegate body executes when Revit processes the event }); private void DeleteWindows() { _deleteWindowsEvent.Raise(); //1. Raise returns immediately, the delegate is queued } ``` -------------------------------- ### Suppress Failures and Dialogs in Revit Context Source: https://github.com/nice3point/revittoolkit/blob/main/Changelog.md Use Context.SuppressFailures and Context.SuppressDialogs to manage Revit error messages and dialogs during transactions. These methods provide automatic resolution without user interruption. ```C# using (var context = new Context()) { context.SuppressFailures(); // Your code here } using (var context = new Context()) { context.SuppressDialogs(); // Your code here } ``` -------------------------------- ### ExternalEventOptions.AllowDirectInvocation Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Configures an external event to allow direct invocation on the calling thread when Revit is in API mode, avoiding queuing. ```csharp private readonly ExternalEvent _deleteWindowsEvent = new(application => { //Execution logic }, ExternalEventOptions.AllowDirectInvocation); ``` -------------------------------- ### Define External Event with Source Generator Source: https://github.com/nice3point/revittoolkit/blob/main/Changelog.md Use the [ExternalEvent] attribute on a method within a partial class to automatically generate typed event properties. This eliminates boilerplate code for defining external events. ```csharp public partial class MyViewModel : ObservableObject { [ExternalEvent] private void DeleteWindows(UIApplication application) { var document = application.ActiveUIDocument.Document; using var transaction = new Transaction(document, "Delete windows"); transaction.Start(); document.Delete(document.GetInstanceIds(BuiltInCategory.OST_Windows)); transaction.Commit(); } [RelayCommand] private void DeleteWindows() { DeleteWindowsEvent.Raise(); } } // Generates: // public IExternalEvent DeleteWindowsEvent => field ??= new ExternalEvent(DeleteWindows); // public IAsyncExternalEvent DeleteWindowsAsyncEvent => field ??= new AsyncExternalEvent(DeleteWindows); ``` -------------------------------- ### Raise External Event Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Call the Raise method on the generated event property to trigger the annotated method. ```csharp public partial class MyViewModel { private void DeleteCommand() { DeleteWindowsEvent.Raise(); } } ``` -------------------------------- ### Check if Revit is in API Mode Source: https://github.com/nice3point/revittoolkit/blob/main/Changelog.md Use the IsRevitInApiMode property to determine if Revit is currently operating in API mode. This is useful for conditional logic within your add-in. ```C# var isInApiMode = Context.IsRevitInApiMode; ``` -------------------------------- ### Enable Direct Invocation for ExternalEvent Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Set the AllowDirectInvocation property to true on the ExternalEvent attribute to allow direct execution of the event when Revit is in API mode. This is useful for events that need to be triggered immediately without going through the standard event queue. ```csharp [ExternalEvent(AllowDirectInvocation = true)] private void DeleteWindows(UIApplication application) { //Execution logic } ``` -------------------------------- ### Control Saving Shared Coordinates for Revit Links Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Use ISaveSharedCoordinatesCallback to control how Revit handles shared coordinates when unloading or reloading Revit links. Options include saving or not saving link changes. ```C# var linkType = elementId.ToElement(RevitContext.ActiveDocument); linkType.Unload(new SaveSharedCoordinatesCallback()); linkType.Unload(new SaveSharedCoordinatesCallback(SaveModifiedLinksOptions.DoNotSaveLinks)); linkType.Unload(new SaveSharedCoordinatesCallback(type => { if (type.AttachmentType == AttachmentType.Overlay) return SaveModifiedLinksOptions.SaveLinks; return SaveModifiedLinksOptions.DoNotSaveLinks; })); ``` -------------------------------- ### Generic ExternalEvent with Argument Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Utilize ExternalEvent to pass a specific argument to the event handler. This allows for parameterized operations, such as deleting a specific window identified by its ElementId. ```csharp private readonly ExternalEvent _deleteWindowEvent = new((application, elementId) => { var document = application.ActiveUIDocument.Document; using var transaction = new Transaction(document, "Delete window"); transaction.Start(); document.Delete(elementId); transaction.Commit(); //2. The delegate body executes with the provided argument }); private void DeleteWindow(ElementId elementId) { _deleteWindowEvent.Raise(elementId); //1. Raise returns immediately, the delegate is queued } ``` -------------------------------- ### Replace Legacy AsyncEventHandler with AsyncExternalEvent Source: https://github.com/nice3point/revittoolkit/blob/main/Changelog.md Update from AsyncEventHandler to AsyncExternalEvent for asynchronous Revit operations. This ensures proper handling of async tasks and results. ```csharp // Before private readonly AsyncEventHandler _handler = new(); private async Task ExecuteAsync() { await _handler.RaiseAsync(app => { app.ActiveUIDocument.Document.Delete(elementId); }); } // After private readonly AsyncExternalEvent _handler = new(app => { app.ActiveUIDocument.Document.Delete(elementId); }); private async Task ExecuteAsync() { await _handler.RaiseAsync(); } ``` -------------------------------- ### Generated External Event Properties Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md The attribute generates IExternalEvent and IAsyncExternalEvent properties based on the annotated method name. ```csharp public partial class MyViewModel { public IExternalEvent DeleteWindowsEvent => field ??= new ExternalEvent(DeleteWindows); public IAsyncExternalEvent DeleteWindowsAsyncEvent => field ??= new AsyncExternalEvent(DeleteWindows); } ``` -------------------------------- ### Handle Duplicate Type Names During Paste Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Implement IDuplicateTypeNamesHandler to manage duplicate type names encountered during a paste operation. Options include aborting the operation or using destination types. ```C# var options = new CopyPasteOptions(); options.SetDuplicateTypeNamesHandler(new DuplicateTypeNamesHandler()); options.SetDuplicateTypeNamesHandler(new DuplicateTypeNamesHandler(args => DuplicateTypeAction.Abort)); options.SetDuplicateTypeNamesHandler(new DuplicateTypeNamesHandler(DuplicateTypeAction.UseDestinationTypes)); ElementTransformUtils.CopyElements(source, elementIds, destination, null, options); ``` -------------------------------- ### Suppress Dialogs in Revit UI Source: https://github.com/nice3point/revittoolkit/blob/main/Readme.md Use RevitContext.BeginDialogSuppressionScope to suppress dialogs during user operations. You can specify a result code or use a custom handler for more control over dialog responses. ```C# using (RevitContext.BeginDialogSuppressionScope()) { //User operations LoadFamilies(); } // Dialogs are restored automatically ``` ```C# using (RevitContext.BeginDialogSuppressionScope(resultCode: 2)) { LoadFamilies(); } ``` ```C# using (RevitContext.BeginDialogSuppressionScope(TaskDialogResult.Ok)) { LoadFamilies(); } ``` ```C# using (RevitContext.BeginDialogSuppressionScope(MessageBoxResult.Yes)) { LoadFamilies(); } ``` ```C# using (RevitContext.BeginDialogSuppressionScope(args => { var result = args.DialogId == "TaskDialog_ModelUpdater" ? TaskDialogResult.Ok : TaskDialogResult.Close; args.OverrideResult((int)result); })) { LoadFamilies(); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.