I am wondering if the following is a bug or at best a documentation inaccuracy of the Windows Search API for a StorageFolder
.
This is a simple UWP app which allows a user to pick a folder and scan this folder deeply to simply count the number of files.
The returned count is consistent with Windows 10's File Explorer if the folder is sitting here for a while, but inconsistent if the folder has been just copied to the C drive from another partition on my laptop. To make the issue clear I copied a folder containing 1768 video and image files into the desktop and run the app on the spot such that Windows 10 did not have the time to index the content.
The C# code (XAML is simple and can be guessed from the C# code)
private async void AppBarButton_Click(object sender, RoutedEventArgs e)
{
var folderPicker = new FolderPicker
{
SuggestedStartLocation = PickerLocationId.Desktop,
ViewMode = PickerViewMode.Thumbnail
};
folderPicker.FileTypeFilter.Add("*");
_folder = await folderPicker.PickSingleFolderAsync();
if (_folder != null)
{
resultStackPanel.Children.Clear();
var indexState = await _folder.GetIndexedStateAsync();
bottomInfoTextBlock.Text = indexState.ToString();
var queryOptions = new QueryOptions { FolderDepth = FolderDepth.Deep };
foreach (IndexerOption indexerOption in Enum.GetValues(typeof(IndexerOption)))
{
queryOptions.IndexerOption = indexerOption;
await CountFilesAsync(queryOptions);
}
}
}
private async Task CountFilesAsync(QueryOptions queryOptions)
{
var textBlock = new TextBlock();
resultStackPanel.Children.Add(textBlock);
if (!_folder.AreQueryOptionsSupported(queryOptions))
{
textBlock.Text = $"Query unsupported for {queryOptions.IndexerOption}";
return;
}
var query = _folder.CreateFileQueryWithOptions(queryOptions);
textBlock.Text = $"{queryOptions.IndexerOption}: Wait, getting files count ...";
var numOfFiles = (await query.GetFilesAsync()).Count;
textBlock.Text = $"{queryOptions.IndexerOption} {numOfFiles}";
}
}
I obtain the following result as I loop through the IndexerOption
Enum
What I expected is that the IndexerOption.UseIndexerWhenAvailable
would return the exact count of 1768
, as it is documented as
Use the system index for content that has been indexed and use the file system directly for content that has not been indexed.
What I worry about is that I would like to avoid using DoNotUseIndexer
Enum
value because of performance as I plan to retrieve thumbnails and extra properties from each the storage file, but this option is the only one that gives the correct count.
I checked out that the Photos app from Microsoft loads only a portion of the content, i.e. as if it uses UseIndexerWhenAvailable
, but it has the capability to update itself as I wait for 1-2 minutes.
Hence I wonder if:
1) My only solution to provide the user with an accurate result is to use the DoNotUseIndexer
Enum
or is it possible to UseIndexerWhenAvailable
or ideally OnlyUseIndexerAndOptimizeForIndexedProperties
but track by some event
when Windows 10 eventually indexed all files to notify my app?
2) What is UseIndexerWhenAvailable
actually doing? It seems inconsistent with its description
Thank you
The following allows to inform the app as the file system changes. In the calling method fire the event
query.ContentsChanged += Query_ContentsChanged;
with
private async void Query_ContentsChanged(IStorageQueryResultBase sender, object args)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
var count = await sender.GetItemCountAsync();
var textBlock = new TextBlock();
resultStackPanel.Children.Add(textBlock);
textBlock.Text = $"Changed {count} {sender.Folder.Name}";
});
}
The local variable count
can be set as a property in the Page and, e.g. OneWay
bound to a XAML TextBlock.Text
with INotifyPropertyChanged
. In this way the value will be updated as Windows indexes all the files and after a minute or so the count reaches the final value of 1768. In addition, a removal or addition of files in the folder will update the UI count. The only caution is if you rename the folder at some point. In this case the app will start counting the default SuggestedStartLocation
, which is the Desktop in my case. Hence the utility of checking sender.Folder.Name
against the picked _folder
(code not shown).