derive DbUpdater from external event and replace Idling diff --git a/RoomEditorApp/App.cs b/RoomEditorApp/App.cs --- a/RoomEditorApp/App.cs +++ b/RoomEditorApp/App.cs @@ -36,7 +36,8 @@ namespace RoomEditorApp /// /// Store the Idling event handler when subscribed. /// - static EventHandler _handler = null; + //static EventHandler _handler = null; + static ExternalEvent _event = null; @@ -211,14 +212,15 @@ namespace RoomEditorApp /// Toggle on and off subscription to /// automatic cloud updates. /// - public static void ToggleSubscription( - EventHandler handler ) + public static ExternalEvent ToggleSubscription( + IExternalEventHandler handler ) // EventHandler { if( Subscribed ) { Debug.Print( "Unsubscribing..." ); - _uiapp.Idling -= _handler; - _handler = null; + //_uiapp.Idling -= _handler; _handler = null; + _event.Dispose(); + _event = null; _buttons[3].ItemText = _subscribe; _timer.Stop(); _timer.Report( "Subscription timing" ); @@ -228,12 +230,14 @@ namespace RoomEditorApp else { Debug.Print( "Subscribing..." ); - _uiapp.Idling += handler; - _handler = handler; + //_uiapp.Idling += handler; + //_handler = handler; + _event = ExternalEvent.Create( handler ); _buttons[3].ItemText = _unsubscribe; _timer = new JtTimer( "Subscription" ); Debug.Print( "Subscribed." ); } + return _event; } public Result OnStartup( @@ -251,7 +255,8 @@ namespace RoomEditorApp { if( Subscribed ) { - _uiapp.Idling -= _handler; + //_uiapp.Idling -= _handler; + _event.Dispose(); } return Result.Succeeded; } diff --git a/RoomEditorApp/CmdSubscribe.cs b/RoomEditorApp/CmdSubscribe.cs --- a/RoomEditorApp/CmdSubscribe.cs +++ b/RoomEditorApp/CmdSubscribe.cs - App.ToggleSubscription( OnIdling ); + + DbUpdater.ToggleSubscription( + commandData.Application ); diff --git a/RoomEditorApp/CmdUpdate.cs b/RoomEditorApp/CmdUpdate.cs --- a/RoomEditorApp/CmdUpdate.cs +++ b/RoomEditorApp/CmdUpdate.cs @@ -96,7 +96,9 @@ namespace RoomEditorApp - DbUpdater updater = new DbUpdater( doc ); + + DbUpdater updater = new DbUpdater( uiapp ); diff --git a/RoomEditorApp/DbUpdater.cs b/RoomEditorApp/DbUpdater.cs --- a/RoomEditorApp/DbUpdater.cs +++ b/RoomEditorApp/DbUpdater.cs @@ -3,14 +3,17 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Threading; +using Autodesk.Revit.ApplicationServices; using Autodesk.Revit.DB; +using Autodesk.Revit.UI; using DreamSeat; #endregion namespace RoomEditorApp { - class DbUpdater + class DbUpdater : IExternalEventHandler @@ -38,7 +41,12 @@ namespace RoomEditorApp + /// + /// Revit UI application. + /// + UIApplication _uiapp = null; @@ -47,6 +55,23 @@ namespace RoomEditorApp + /// + /// External event to raise event + /// for pending database changes. + /// + static ExternalEvent _event = null; + + /// + /// Separate thread running loop to + /// check for pending database changes. + /// + static Thread _thread = null; @@ -54,12 +79,13 @@ namespace RoomEditorApp - public DbUpdater( Document doc ) + public DbUpdater( UIApplication uiapp ) { using( JtTimer pt = new JtTimer( "DbUpdater ctor" ) ) { - _doc = doc; - _creapp = doc.Application.Create; + _uiapp = uiapp; + _creapp = _uiapp.Application.Create; } } @@ -67,9 +93,11 @@ namespace RoomEditorApp /// Update a piece of furniture. /// Return true if anything was changed. /// - bool UpdateBimFurniture( + bool UpdateBimFurniture( DbFurniture f ) { + Document doc = _uiapp.ActiveUIDocument.Document; + @@ -82,7 +110,7 @@ namespace RoomEditorApp - Element e = _doc.GetElement( f.Id ); + Element e = doc.GetElement( f.Id ); @@ -131,24 +159,24 @@ namespace RoomEditorApp - using( Transaction tx = new Transaction( - _doc ) ) + using( Transaction tx = new Transaction( + doc ) ) - ElementTransformUtils.MoveElement( - _doc, e.Id, translation ); + ElementTransformUtils.MoveElement( + doc, e.Id, translation ); - ElementTransformUtils.RotateElement( - _doc, e.Id, axis, rotation ); + ElementTransformUtils.RotateElement( + doc, e.Id, axis, rotation ); @@ -165,10 +193,12 @@ namespace RoomEditorApp { using( JtTimer pt = new JtTimer( "UpdateBim" ) ) { + Document doc = _uiapp.ActiveUIDocument.Document; + // Retrieve all room unique ids in model: FilteredElementCollector rooms - = new FilteredElementCollector( _doc ) + = new FilteredElementCollector( doc ) .OfClass( typeof( SpatialElement ) ) .OfCategory( BuiltInCategory.OST_Rooms ); @@ -225,5 +255,133 @@ namespace RoomEditorApp + public void Execute( UIApplication a ) + { + UpdateBim(); + } + + public string GetName() + { + return string.Format( + "{0} DbUpdater", App.Caption ); + } + + /// + /// Count total number of checks for + /// database updates made so far. + /// + static int _nLoopCount = 0; + + /// + /// Count total number of checks for + /// database updates made so far. + /// + static int _nCheckCount = 0; + + /// + /// Count total number of database + /// updates requested so far. + /// + static int _nUpdatesRequested = 0; + + /// + /// Wait far a moment before requerying database. + /// + //static Stopwatch _stopwatch = null; + + /// + /// Number of milliseconds to wait and relinquish + /// CPU control before next check for pending + /// database updates. + /// + const int _timeout = 100; + + /// + /// Repeatedly check database status and raise + /// external event when updates are pending. + /// Relinquish control and wait for timeout + /// period between each attempt. Run in a + /// separate thread. + /// + static void CheckForPendingDatabaseChanges() + { + while( true ) + { + ++_nLoopCount; + + Debug.Assert( null != _event, + "expected non-null external event" ); + + if( _event.IsPending ) + { + Util.Log( string.Format( + "CheckForPendingDatabaseChanges loop {0} - " + + "database update event is pending", + _nLoopCount ) ); + } + else + { + using( JtTimer pt = new JtTimer( + "CheckForPendingDatabaseChanges" ) ) + { + ++_nCheckCount; + + Util.Log( string.Format( + "CheckForPendingDatabaseChanges loop {0} - " + + "check for changes {1}", + _nLoopCount, _nCheckCount ) ); + + RoomEditorDb rdb = new RoomEditorDb(); + + if( rdb.LastSequenceNumberChanged( + DbUpdater.LastSequence ) ) + { + _event.Raise(); + + ++_nUpdatesRequested; + + Util.Log( string.Format( + "database update pending event raised {0} times", + _nUpdatesRequested ) ); + } + } + } + + // Wait a moment and relinquish control before + // next check for pending database updates. + + Thread.Sleep( _timeout ); + } + } + + public static void ToggleSubscription( + UIApplication uiapp ) + { + _event = App.ToggleSubscription( + new DbUpdater( uiapp ) ); + + if( null == _event ) + { + _thread.Abort(); + _thread = null; + } + else + { + // Start new thread to regularly check + // database status and raise external event + // when updates are pending. + + _thread = new Thread( + CheckForPendingDatabaseChanges ); + + _thread.Start(); + } + }