internal SearchManager( ILogSourcesManager sources, ISynchronizationContext modelSynchronization, IHeartBeatTimer heartBeat, ISearchObjectsFactory factory, IChangeNotification changeNotification ) { this.sources = sources; this.factory = factory; this.changeNotification = changeNotification; this.combinedSearchResult = factory.CreateCombinedSearchResult(this); this.combinedResultUpdateInvoker = new AsyncInvokeHelper( modelSynchronization, UpdateCombinedResult); this.combinedResultNeedsLazyUpdateFlag = new LazyUpdateFlag(); sources.OnLogSourceAdded += (s, e) => { results.ForEach(r => r.FireChangeEventIfContainsSourceResults(s as ILogSource)); }; sources.OnLogSourceRemoved += (s, e) => { results.ForEach(r => r.FireChangeEventIfContainsSourceResults(s as ILogSource)); // Search result is fully disposed if it contains messages // only from disposed log sources. // Fully disposed results are automatically dropped. var toBeDropped = results.Where( r => r.Results.All(sr => sr.Source.IsDisposed)).ToHashSet(); var nrOfFullyDisposedResults = DisposeResults(toBeDropped); if (nrOfFullyDisposedResults > 0 && SearchResultsChanged != null) { SearchResultsChanged(this, EventArgs.Empty); } if (nrOfFullyDisposedResults > 0) { changeNotification.Post(); combinedResultNeedsLazyUpdateFlag.Invalidate(); } }; heartBeat.OnTimer += (s, e) => { if (e.IsNormalUpdate && combinedResultNeedsLazyUpdateFlag.Validate()) { combinedResultUpdateInvoker.Invoke(); } }; }