namespace RhMcp; /// /// Owns a per open document, wiring them up on construction and /// tearing them down on . Tracks documents via Rhino's open/close events. /// internal sealed class CommandInterceptorHost : IDisposable { private Dictionary Interceptors { get; } = new(); private bool Attached { get; set; } public CommandInterceptorHost() { Attached = true; RhinoDoc.BeginOpenDocument += OnBeginOpen; RhinoDoc.NewDocument += OnNewDocument; RhinoDoc.CloseDocument += OnClose; foreach (RhinoDoc doc in RhinoDoc.OpenDocuments()) Add(doc); } public void Dispose() { if (!Attached) return; Attached = false; RhinoDoc.BeginOpenDocument -= OnBeginOpen; RhinoDoc.NewDocument -= OnNewDocument; RhinoDoc.CloseDocument -= OnClose; foreach (CommandInterceptor interceptor in Interceptors.Values) interceptor.Dispose(); Interceptors.Clear(); } private void OnBeginOpen(object? sender, DocumentOpenEventArgs e) => Add(e.Document); private void OnNewDocument(object? sender, DocumentEventArgs e) => Add(e.Document); private void OnClose(object? sender, DocumentEventArgs e) { if (Interceptors.Remove(e.DocumentSerialNumber, out CommandInterceptor? interceptor)) interceptor.Dispose(); } private void Add(RhinoDoc? doc) { if (doc is null || Interceptors.ContainsKey(doc.RuntimeSerialNumber)) return; Interceptors[doc.RuntimeSerialNumber] = new CommandInterceptor(doc); } }