private void OnProgressUpdated(ref SearchStatistics searchStatistics, double progress)
        {
            latestSearchStatistics.Set(ref searchStatistics);

            // Don't queue up new progress updates if progress is already updating
            // This prevents overloading WPF dispatcher queue, making UI more responsive
            if (isProgressUpdating)
            {
                return;
            }

            isProgressUpdating = true;

            Dispatcher.InvokeAsync(() =>
            {
                if (!double.IsNaN(progress))
                {
                    progressBar.IsIndeterminate = false;
                    progressBar.Value           = 100.0 * progress;
                }

                var statsSnapshot = latestSearchStatistics.Get();
                UpdateStats(ref statsSnapshot);

                isProgressUpdating = false;
            }, DispatcherPriority.Input);
        }
 private void UpdateStats(ref SearchStatistics searchStatistics)
 {
     resultsViewModel.DirectoriesEnumerated                = searchStatistics.directoriesEnumerated;
     resultsViewModel.FilesEnumerated                      = searchStatistics.filesEnumerated;
     resultsViewModel.FileContentsSearched                 = searchStatistics.fileContentsSearched;
     resultsViewModel.ResultsFound                         = searchStatistics.resultsFound;
     resultsViewModel.TotalEnumeratedFilesSizeInBytes      = searchStatistics.totalFileSize;
     resultsViewModel.TotalContentSearchedFilesSizeInBytes = searchStatistics.scannedFileSize;
     resultsViewModel.SearchTimeInSeconds                  = searchStatistics.searchTimeInSeconds;
 }
        private void OnSearchDone(ref SearchStatistics searchStatistics)
        {
            latestSearchStatistics.Set(ref searchStatistics);

            Dispatcher.InvokeAsync(async() =>
            {
                if (!isClosing)
                {
                    var statsSnapshot = latestSearchStatistics.Get();
                    UpdateStats(ref statsSnapshot);
                    progressBar.IsIndeterminate = false;
                    progressBar.IsEnabled       = false;
                    progressBar.Value           = 100;
                }

                await CleanupSearchOperationIfNeeded();
                windowGCHandle.Free();
            }, DispatcherPriority.Input);
        }