BIMGrove

Library

Add text, images, buttons, pricing blocks, forms, and documentation content here.


New Section

Start building this page.

Use the Add Block controls to add content inside this page.

Developer Reference

Extending the palette.

Custom Action Packs, JSON palette schemas, and the security model are all first-class extensibility surfaces.

🧩 Custom Action Packs

Implement IActionPack and IPaletteAction in any assembly. Ship a manifest.json alongside it. SHA-256 hash is validated before loading.

public class MyActionPack : IActionPack { public string PackId => "MyFirm.CoreActions"; public string PackName => "Core Actions"; public IEnumerable<IPaletteAction> GetActions() { yield return new PlaceEquipmentAction(); } }

📄 Manifest JSON

Each Action Pack ships a manifest.json. The assembly_sha256 field is validated on load unless allow_unsigned_action_packs is set in security.json.

{ "pack_id": "MyFirm.CoreActions", "assembly": "MyFirm.CoreActions.dll", "assembly_sha256": "e3b0c44298fc...", "entry_point_type": "MyFirm.MyActionPack" }

🗂️ Palette JSON Schema

Each palette is a JSON array of button rows. Rows are family buttons, action buttons, or separators. Action parameters are a key/value dictionary.

{ "label": "Set Sheet Status", "button_class": "action", "action_id": "BIMGrove.SheetParameter", "action_parameters": { "sheet_parameter.value": "For Review" } }

🏗️ Multi-Version Builds

Separate Release targets for Revit 2023–2027. Each links against that version's Revit API. Conditional flags REVIT2025/2026/2027 gate API features.

Compatibility shims (IsExternalInit, PathCompat, ZipFileCompat) support .NET Framework 4.8 targets for 2023–2024.

UI Specifications

Editor layout & dimensions.

Key structural, behavioral, and visual specifications for the editor window.

Window Architecture

TypeWPF Window (modal)
Threading modelRevit API thread (ShowDialog)
PatternMVVM + INotifyPropertyChanged
Slide transitionsConfigurable (enabled by default)

Layout Panels

Palette list (left)~200px sidebar
Tab list (center-left)Scrollable ListBox
Button list (center)Drag-reorderable ListBox
Properties panel (right)Contextual form
Status barBottom — always visible

Fetch Tab Settings (Fields)

Category slots6 slots (OR logic)
Filter rows4 rows (AND logic)
Script slots2 script paths
Template pathsPer-version (2023–2027)

Save & Persistence

Palette JSONWritten on Save button
Meta JSONTab order, format, settings
Config JSONPalette registry, UI settings
Indented outputWriteIndented = true
Developer Reference

How the editor is built.

Key architecture patterns, services, and extension points for developers working with the editor codebase.

🏗️ MVVM Architecture

PaletteEditorViewModel is the single root ViewModel. It exposes ObservableCollections for palettes, tabs, and button rows. Code-behind is limited to UI-only concerns (drag, focus, animation).

public ObservableCollection<EditorTabRow> Tabs { get; } public ObservableCollection<EditorPaletteRow> ButtonRows { get; } public bool IsDirty => SelectedButtonRow?.IsDirty ?? false;

💾 PaletteEditorDataService

All JSON read/write is centralized here. Loads config.json, per-palette JSON files, and _meta.json sidecars. Save operations are atomic — full file written with WriteIndented = true.

IReadOnlyList<EditorPaletteSummary> palettes = new PaletteEditorDataService().LoadPalettes(); _dataService.SaveButtonRows(jsonPath, updatedRows);

🔄 Dirty State Model

Both EditorPaletteRow and EditorTabRow follow the same dirty-tracking pattern. CaptureLoadedState() snapshots all field values. IsDirty compares to the snapshot. ResetToLoadedState() reverts.

row.CaptureLoadedState(); // snapshot after load bool changed = row.IsDirty; // any field changed? row.ResetToLoadedState(); // revert to snapshot

🩺 PaletteValidationService

Accepts EditorPaletteRow objects, produces a PaletteHealthReport. Checks icon paths, source paths, action IDs, required parameters, and meta-JSON consistency. Results scoped by tab.

var report = new PaletteValidationService() .Validate(paletteRows, metaJson); foreach (var issue in report.Issues) Console.WriteLine($"[{issue.Severity}] {issue.Message}");