Table of Contents

TDV - Transfer Drafting Views

TDV (Transfer Drafting Views) is a tool for importing and exporting drafting views between Revit documents and a central library. It enables teams to maintain a shared collection of standard drafting views that can be distributed across projects.

Source: src/Tools/Common/TDV/manifest.yml:1-45

Overview

TDV provides two primary operations:

  1. Export to Library - Copy drafting views from the active document to a central library file
  2. Import from Library - Copy drafting views from a library file to the active document

The tool handles worksharing, creates local copies for edits, and synchronizes changes back to the central library file after export operations.

Source: src/Tools/Common/TDV/Features/TdvExportCommand.cs:18-27

Features

Core Capabilities

  • Bi-directional transfer - Import and export drafting views between documents
  • View type mapping - Map source view types to destination view types, or retain original type
  • Conflict detection - Real-time detection of naming conflicts with existing views
  • Replace mode - Option to replace existing views with the same name
  • Preview panel - Live preview of selected drafting views with pan/zoom support
  • Batch transfer - Transfer multiple views in a single operation
  • Transaction grouping - All transfers wrapped in a transaction group for atomicity
  • Progress tracking - Per-view progress feedback during transfer operations

Source: src/Tools/Common/TDV/Revit/Services/TdvService.cs:106-330

Crash Hardening (2026-02-07)

The TDV import/export apply path was hardened after a Revit 2026 hard-crash investigation:

  • Destination-bound transactions - The transfer group and per-view transactions are now started against the explicit destination Document, not implicitly against ActiveUIDocument.
  • Cross-document safety checks - TDV now validates that source/destination contexts are valid live documents and not the same document.
  • Transfer run diagnostics - Transfer start logs include run id plus source/destination title and path to improve post-crash forensics.
  • Non-activating library open - TDV now opens library files with Application.OpenDocumentFile(...) (no activate) so the host model stays active during transfer and cleanup.
  • Cleanup-safe close path - TDV commands now use best-effort close (TryCloseAsync) for library cleanup to prevent cleanup-only close failures from surfacing as command failure banners.

Source: src/Tools/Common/TDV/Revit/Services/TdvService.cs:106-372 Source: src/Tools/Common/TDV/Revit/Services/TdvDocumentService.cs:186-246 Source: src/Tools/Common/TDV/Revit/Services/TdvDocumentService.cs:137-168 Source: src/Tools/Common/TDV/Features/TdvImportCommand.cs:120-130 Source: src/Tools/Common/TDV/Features/TdvExportCommand.cs:143-168 Source: src/DBTools.Core/Revit/Transactions/ITransactionGroupService.cs:5-18 Source: src/DBTools.Core/Revit/Transactions/CallGateTransactionGroupService.cs:99-280

Library Management

  • Multiple library files - Configure multiple library files with fallback paths
  • Path validation - Automatic validation of library file accessibility
  • Local copy workflow - Creates local copies from central files for worksharing
  • Automatic sync - Syncs changes back to central after export with detailed comments

Source: src/Tools/Common/TDV/Revit/Services/TdvDocumentService.cs:26-126

View Transfer Details

When transferring views, TDV:

  1. Creates or prepares the destination view with the selected view type
  2. Copies the view scale and description parameters
  3. Copies all elements from the source view (excluding viewports, title blocks, schedules, etc.)
  4. Copies element graphic overrides from source to destination

Source: src/Tools/Common/TDV/Revit/Services/TdvOps.cs:145-189

View Type Resolution Rules

The row View Type combobox is destination-scoped for the active transfer direction:

  • Import (library -> host): combobox options are drafting view types from the host document.
  • Export (host -> library): combobox options are drafting view types from the library document.

Retain Original always resolves to the source view's drafting type name for that row. If that type name is missing in the destination document, TDV creates it by duplicating an existing destination drafting ViewFamilyType and renaming the duplicate.

If source type name resolution fails, TDV records a per-view SourceTypeNameUnavailable error and does not silently fall back.

Source: src/Tools/Common/TDV/Revit/Services/TdvService.cs:47-95 Source: src/Tools/Common/TDV/Revit/Services/TdvService.cs:186-213 Source: src/Tools/Common/TDV/Revit/Services/TdvOps.cs:52-99 Source: src/Tools/Common/TDV/Revit/Services/TdvOps.cs:233-277

Architecture

TDV follows the MVVM pattern with a clean separation between UI, business logic, and Revit API operations.

Project Structure

src/Tools/Common/TDV/
├── Bootstrap/               # DI registration
├── Contracts/               # Interfaces and DTOs
├── DesignTime/              # Design-time view models
├── Features/                # Command implementations
├── Properties/              # Design-time resources
├── Revit/Services/          # Revit API operations
├── Settings/                # Configuration models
├── Tests/                   # Unit tests
└── UI/
    ├── ViewModels/          # MVVM view models
    └── Views/               # WPF views

Service Registration

Services are registered as scoped to properly handle Revit's run-scope dependencies:

Source: src/Tools/Common/TDV/Bootstrap/TdvServiceExtensions.cs:11-33

services.AddScoped<ITdvTransferService>(sp =>
    new TdvService(gate, tx, groups, logger));
services.AddScoped<ITdvLibraryService>(sp =>
    new TdvLibraryService(settings, RevitInstanceIdentifier.RevitYear));
services.AddScoped<ITdvDocumentService, TdvDocumentService>();

Key Interfaces

Interface Implementation Purpose
ITdvTransferService TdvService Core transfer operations
ITdvLibraryService TdvLibraryService Library path management
ITdvDocumentService TdvDocumentService Document open/close/sync
ITdvContext TdvService.RevitTdvContext Abstraction over Revit Document

Source: src/Tools/Common/TDV/Contracts/ITdvTransferService.cs:1-23

Transfer Service Operations

The ITdvTransferService interface defines:

Method Description
BuildViewItemsAsync Collects drafting views from source document
ApplySelectionAsync Executes the transfer operation
WouldConflictAsync Checks for naming conflicts
ExportPreviewAsync Generates preview image for a view

Source: src/Tools/Common/TDV/Contracts/ITdvTransferService.cs:6-22

UI Components

Main Window (TdvWindow)

The main transfer window provides:

  • Filter controls - Filter by view type and search by name
  • Data grid - Lists all drafting views with transfer options
  • Preview panel - Shows selected view with pan/zoom
  • Status bar - Displays selection counts and transfer results

Source: src/Tools/Common/TDV/UI/Views/TdvWindow.xaml:1-537

The TDV window now binds its overlay instance to itself (ProgressOverlayService.For(this)), ensuring overlay ownership and dispatcher affinity are tied to the active TDV host window.

Source: src/Tools/Common/TDV/UI/Views/TdvWindow.xaml.cs:59-74

ViewModel (TdvWindowViewModel)

Key properties and commands:

Property Type Description
Items ObservableCollection<TdvViewItem> Filtered list of views
Search string Search filter text
SelectedViewTypeFilter string View type filter
SelectedItem TdvViewItem Currently selected view
PreviewSource ImageSource Preview image
HasAnyConflict bool Indicates naming conflicts
Status string Status bar text
Command Description
ApplySelectionCommand Executes the transfer
ClearSelectedCommand Clears all selections
ClearSearchCommand Clears search filter

Source: src/Tools/Common/TDV/UI/ViewModels/TdvWindowViewModel.cs:22-409

View Item (TdvViewItem)

Represents a single drafting view in the UI:

Property Type Description
SourceViewId int Revit element ID
ViewName string Editable view name
ViewType string Selected destination type
ViewTypeName string Original source type name
Checked bool Selected for transfer
Replace bool Replace if exists
HasConflict bool Has naming conflict
HasTypeWarning bool Source type unavailable
RowState string Transfer status (pending/success/failure)

Source: src/Tools/Common/TDV/UI/ViewModels/TdvViewItem.cs:9-106

Preview Features

The preview panel supports:

  • Debounced loading - 200ms debounce prevents excessive exports
  • LRU cache - Caches up to 32 preview images
  • Pan and zoom - Interactive image manipulation via ImagePanZoomBehavior
  • Zoom Extents - Fits + centers the preview image in the viewport
  • Best-effort cropping - Preview exports are cropped to content bounds (non-background pixels) so extents-based zoom targets the real view content
  • Dark theme background - Consistent preview appearance (RGB: 43, 44, 61)

Source: src/Tools/Common/TDV/UI/ViewModels/TdvWindowViewModel.cs:74-81 Source: src/Tools/Common/TDV/Revit/Services/TdvOps.cs:19-28 Source: src/Tools/Common/TDV/UI/Behaviors/TdvImageZoomExtentsBehavior.cs:72 Source: src/Tools/Common/TDV/Revit/Services/TdvOps.cs:350

Cache Locations

TDV stores transient files under %APPDATA%\\DBTools\\Cache\\TDV\\:

  • LibraryLocals\\ - Per-operation workshared locals (deleted after the operation closes the library document)
  • Preview\\ - Per-window preview export images

Source: src/Tools/Common/TDV/Services/TdvCachePaths.cs:13 Source: src/Tools/Common/TDV/Revit/Services/TdvDocumentService.cs:203 Source: src/Tools/Common/TDV/UI/ViewModels/TdvWindowViewModel.cs:446

Settings Configuration

Library Settings

TDV uses the MasterLibrarySettings class to store library file configurations:

public sealed class MasterLibrarySettings
{
    public IList<LibraryFileEntry> Files { get; set; }
    public bool HasWarnings { get; set; }
}

public sealed class LibraryFileEntry
{
    public string? MainPath { get; set; }
    public string? FallbackPath { get; set; }
    public string? Alias { get; set; }
}

Source: src/Tools/Common/TDV/Settings/MasterLibrarySettings.cs:1-8 Source: src/Tools/Common/TDV/Settings/LibraryFileEntry.cs:1-8

Each library entry supports:

  • Main path - Primary path to the library RVT file
  • Fallback path - Alternative path (e.g., for different network locations)
  • Alias - Optional friendly name used in the Import/Export library picker

Settings Pack

The LibrarySettingsPackContext provides the settings UI with:

  • Tree-based library file management
  • Add/remove library files
  • Add/remove fallback paths
  • Real-time path validation
  • Pending changes tracking

Source: src/Tools/Common/TDV/Settings/LibrarySettingsPackContext.cs:19-352

Settings Path Presentation

Library paths in settings are rendered with:

  • Validation icon at the left of each tree row (green check / red error)
  • Tooltip showing the full absolute path
  • Compact display text that keeps root + filename + the final 3 folder levels

This avoids horizontal scrolling while preserving useful location context.

Source: src/Tools/Common/TDV/Settings/LibrarySettingsPackView.xaml:33-77 Source: src/Tools/Common/TDV/Settings/LibrarySettingsPackContext.cs:296-313 Source: src/Tools/Common/TDV/Settings/LibraryPathDisplayFormatter.cs:1-63

Path Validation

Library paths are validated for:

  • File existence
  • .rvt extension
  • Revit version compatibility (file's saved version must match the current Revit session)
  • Accessibility

Invalid paths trigger a settings warning that disables the import/export commands.

Source: src/Tools/Common/TDV/Revit/Services/TdvLibraryService.cs:100-160

Library warnings are evaluated on startup, so the Import/Export ribbon tools may be disabled immediately if configured library paths are invalid.

Source: src/DBTools.App/Addin/AddinEntry.cs:324 Source: src/DBTools.Core/Settings/Features/DbtSettingsStartupWarningEvaluator.cs:36

Revit Version Validation

Library files are checked at two points to prevent version mismatches:

  1. Validation time (TdvLibraryService.ValidatePath): Uses BasicFileInfo.Extract() and RevitInstanceIdentifier.ParseRevitYear() to compare the file's saved Revit version against the current session. Mismatched files are marked invalid with a descriptive failure reason and excluded from the accessible library list.

  2. Open time (TdvDocumentService.OpenLibraryAsync): A belt-and-suspenders check before opening. Throws InvalidOperationException if the file version doesn't match, which is caught by the command's try/catch and displayed as a banner.

This prevents two dangerous scenarios:

  • Workshared files: WorksharingUtils.CreateNewLocal() would throw a version mismatch error at open time
  • Non-workshared files: Revit would silently upgrade the file, which is destructive

Source: src/Tools/Common/TDV/Revit/Services/TdvLibraryService.cs:135-155 Source: src/Tools/Common/TDV/Revit/Services/TdvDocumentService.cs:30-45

Dialog Suppression During Document Open

When opening a library document, the TDV commands wrap the OpenLibraryAsync call with DialogSuppressionHook.SuppressAvailabilityDialogs(). This suppresses cascading Revit "availability command failed" TaskDialogs (TaskDialog_External_Tools_Command_Failure) that can occur during document switching when Revit re-evaluates IExternalCommandAvailability checks.

The suppression uses a scoped pattern mechanism: a regex pattern is pushed onto a thread-safe stack and automatically removed when the using scope ends.

Limitation: DialogBoxShowing suppression only applies to Revit-hosted dialogs (TaskDialogs and some built-in dialogs). It cannot reliably prevent other add-ins from opening their own WPF/Win32 modal windows during document open/close operations. When third-party modal dialogs block TDV flows, the practical mitigation is to disable the conflicting add-in(s) for that Revit session or expand DialogSuppression patterns for known Revit TaskDialogs.

Source: src/Tools/Services/DialogSuppression/DialogSuppressionHook.cs Source: src/Tools/Common/TDV/Features/TdvImportCommand.cs:92-101 Source: src/Tools/Common/TDV/Features/TdvExportCommand.cs:96-105

Manifest Configuration

The tool is configured via manifest.yml:

id: DBTools.TDV
assembly: DBTools
moduleType: DBTools.TDV.TdvToolModule
order: 0

sandboxWindows:
  - id: DBTools.TDV.Main
    displayName: "Transfer Drafting Views"
    group: "Common"
    windowType: "DBTools.TDV.UI.Views.TdvWindow"

tool:
  settings:
    configSection: Core.MasterLibrary
  settingsPacks:
    - key: core.library
      title: "Library Files"
      warnings:
        - id: core.library.invalid
          title: "Library Paths Invalid"
          message: "One or more library file paths are invalid..."
          disableTools:
            - DBTools.ExportToLibrary
            - DBTools.ImportFromLibrary

  ribbonTools:
    - internalName: DBTools.ExportToLibrary
      commandType: DBTools.TDV.Features.TdvExportCommand
      availabilityType: DBTools.App.Tools.Availability.DbtDocumentAvailability
      runProfile: InlineUi
      displayText: "Export\nTo Library"
      iconBaseKey: export
      tooltip: "Export drafting views to the library"
      controlKind: StackedButtonItem
      splitGroup: library_transfer

    - internalName: DBTools.ImportFromLibrary
      commandType: DBTools.TDV.Features.TdvImportCommand
      availabilityType: DBTools.App.Tools.Availability.DbtDocumentAvailability
      runProfile: InlineUi
      displayText: "Import\nFrom Library"
      iconBaseKey: import
      tooltip: "Import drafting views from the library"
      controlKind: StackedButtonItem
      splitGroup: library_transfer

Source: src/Tools/Common/TDV/manifest.yml:1-45

Ribbon Configuration

Property Export Import
Internal Name DBTools.ExportToLibrary DBTools.ImportFromLibrary
Command TdvExportCommand TdvImportCommand
Run Profile InlineUi InlineUi
Icon export import
Control Kind StackedButtonItem StackedButtonItem
Split Group library_transfer library_transfer

Error Handling

Per-View Error Codes

Transfer failures are categorized by error code:

Code Description
Unknown Unspecified error
DestinationTypeMissing Target view type not found
SourceTypeNameUnavailable Cannot read source view type
CreateViewFailed Failed to create destination view
CopyElementsFailed Failed to copy view elements
OverridesFailed Failed to copy graphic overrides

Source: src/Tools/Common/TDV/Contracts/TdvPerViewErrorCode.cs:1-12

Error Reporting

After each transfer attempt, TDV now always surfaces result UX:

  • Top banner on the TDV window (success/warning) with selected/processed/result counts
  • Summary alert with:
    • Selected, processed, added, replaced, and error counts
    • Optional per-view issue table when failures exist
    • Action buttons: Accept and Transfer More and Close Tool
    • Copy-to-clipboard for per-view issue rows

TDV also records and surfaces selection accountability:

  • Transfer logs now include selected view identifiers/names (bounded preview)
  • Result payload includes SelectedCount, ProcessedCount, and Cancelled
  • UI warns when selected/processed counts diverge

Source: src/Tools/Common/TDV/UI/Views/TdvWindow.xaml.cs:111-231 Source: src/Tools/Common/TDV/UI/ViewModels/TdvWindowViewModel.cs:274-348 Source: src/Tools/Common/TDV/Contracts/TdvApplySelectionResult.cs:5-13 Source: src/Tools/Common/TDV/Revit/Services/TdvService.cs:125-372

Revit API Operations

Getting Drafting Views

new FilteredElementCollector(doc)
    .OfClass(typeof(View))
    .WhereElementIsNotElementType()
    .Cast<View>()
    .Where(v => v.ViewType == ViewType.DraftingView && !v.IsTemplate)

Source: src/Tools/Common/TDV/Revit/Services/TdvOps.cs:30-39

Copying View Contents

Elements are copied using ElementTransformUtils.CopyElements with a custom IDuplicateTypeNamesHandler that uses destination types when duplicates are found.

Source: src/Tools/Common/TDV/Revit/Services/TdvOps.cs:145-162

Skipped Categories

The following categories are excluded from copy operations:

  • Title Blocks
  • Viewports
  • Views
  • Schedules
  • Guide Grids

Source: src/Tools/Common/TDV/Revit/Services/TdvOps.cs:13-16

Command Reference

Library Selection Dialog Sizing

TDV export/import library selection dialogs override default alert dimensions to a compact tool-specific size:

  • Width: 640
  • Height: 420
  • MinWidth: 520
  • MinHeight: 340

Source: src/Tools/Common/TDV/Features/TdvAlertWindowOptions.cs:1-17 Source: src/Tools/Common/TDV/Features/TdvExportCommand.cs:75-84 Source: src/Tools/Common/TDV/Features/TdvImportCommand.cs:70-79

Library Picker Display

The library picker list uses:

  • Alias (when configured) for a short readable name
  • A compact tail-of-path suffix when no alias is present (keeps the dialog narrow without losing location context)

Source: src/Tools/Common/TDV/Features/TdvImportCommand.cs:70 Source: src/Tools/Common/TDV/Features/TdvExportCommand.cs:75 Source: src/Tools/Common/TDV/Settings/LibraryPathDisplayFormatter.cs:8

Export Command Flow

  1. Validate library paths are configured
  2. Prompt user to select a library file
  3. If workshared, create a per-operation local copy under the TDV cache folder
  4. Open library document
  5. Show TdvWindow for view selection
  6. Execute transfer to library
  7. Sync changes to central with comment
  8. Close library and reactivate original document

Source: src/Tools/Common/TDV/Features/TdvExportCommand.cs:31-137

Import Command Flow

  1. Validate library paths are configured
  2. Prompt user to select a library file
  3. If workshared, create a per-operation local copy under the TDV cache folder
  4. Open library document
  5. Show TdvWindow for view selection
  6. Execute transfer to active document
  7. Close library (no sync needed)

Source: src/Tools/Common/TDV/Features/TdvImportCommand.cs:27-107

Cross-References

Testing

TDV includes unit tests for:

  • TdvViewItem - View model behavior
  • TdvLibraryService - Path validation and library management
  • TdvAdapter - Service adapter tests

Source: src/Tools/Common/TDV/Tests/


Last updated: March 2026