问题
I am using for a UWP app the FileInformationFactory
to retrieve a Virtualized vector of files object which are cast to a FileInformation
and displayed in a GridView
.
I want to query a folder on a SD card plugged onto my laptop and compare the virtualization of the GridView
when this folder is in a FullyIndexed
location, such as my Desktop.
This SD card has a folder containing 15,000 text files of zero bytes. Each file is named x.txt
where x runs from 1-15000 (this can be generated in a folder of your choice by clicking the Add button in the code below; it takes a minute or so on my machine, but remember to do it only once!).
The result is displayed in a GridView
where I display the name of each file.
In a FullyIndexed
location I can scroll up and down the GridView
very fast, even using the vertical scrollbar very quickly and erratically and the GridView
will always manage to show up the name of each file, albeit some delays of a few seconds.
In a NotIndexed
location such an SD card or an external Hard Drive, the GridView displays the items as I scroll slowly but very quickly it looses track of the items as I scroll up and down too quickly, e.g. when using the vertical scroll bar with my trackpad. Waiting does not help. The app still responds but nothing gets displayed. Even when scrolling up to the top, only the first element name is shown and the only choice is to re-display the whole and scroll smoothly.
How can I solve this issue in a NotIndexed
location? I do not want to retrieve the files one by one into memory as this takes up too much time and for real photos that will eat the user's RAM too quickly. Hence the use of the GetVirtualizedFilesVector
.
I thought that would be a Virtualization of the GridView but it seems not the case, and furthermore the app works well with real 17k photos but only on a FullyIndexed
location.
Thank you
<Page
x:Class="Virtualization.Scenario4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ba="using:Windows.Storage.BulkAccess"
xmlns:local="using:Virtualization"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="48"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.ColumnSpan="1" Orientation="Horizontal"
BorderThickness="0,0,2,2">
<AppBarButton x:Name="FolderPickerButton" Icon="Folder"
LabelPosition="Collapsed" Label="Select Folder"
Click="FolderPickerButton_Click"/>
<AppBarButton Icon="ViewAll"
LabelPosition="Collapsed"
Click="ViewAllAppBarButton_Click"/>
<AppBarButton Icon="Add"
LabelPosition="Collapsed"
Click="AddFilesAppBarButton_Click"/>
<AppBarSeparator/>
</StackPanel>
<GridView Grid.Row="1" Grid.Column="1"
ItemsSource="{x:Bind ItemCollectionView, Mode=OneWay}" IsItemClickEnabled="True" ItemClick="GridView_ItemClick">
<GridView.ItemTemplate>
<DataTemplate x:DataType="ba:FileInformation">
<Grid>
<TextBlock MinWidth="80" Text="{Binding Name}" TextWrapping="WrapWholeWords"/>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
<ListView Grid.Row="1" Grid.Column="2" ItemsSource="{x:Bind Information, Mode=OneWay}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
public sealed partial class Scenario4 : Page, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
public Scenario4()
{
this.InitializeComponent();
}
private ICollectionView _fileCollectionView;
private StorageFolder _folder;
private IStorageQueryResultBase _query;
private FileInformationFactory _fileInformationFactory;
private object _vector;
public CollectionViewSource CollectionViewSource { get; set; } = new CollectionViewSource();
public ICollectionView ItemCollectionView
{
get { return _fileCollectionView; }
set
{
if (_fileCollectionView != value)
{
_fileCollectionView = value;
OnPropertyChanged(nameof(ItemCollectionView));
}
}
}
public ObservableCollection<string> Information { get; private set; } = new ObservableCollection<string>();
private async void FolderPickerButton_Click(object sender, RoutedEventArgs e)
{
var _pickedFolder = await PickFolderAsync();
if (_pickedFolder == null)
{
Information.Add("Choose a folder");
return;
}
Information.Add("Generate 15k files with the Add button if not done already, otherwise click the ViewAll button");
_folder = _pickedFolder;
}
private async void Query_ContentsChanged(IStorageQueryResultBase sender, object args)
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
Information.Add($"Contents Changed {sender.Folder.Name} {args}");
});
}
private void View_VectorChanged(IObservableVector<object> sender, IVectorChangedEventArgs @event)
{
if (@event.CollectionChange == CollectionChange.Reset)
{
Information.Add($"Vector Changed {@event.CollectionChange} ItemCount: {sender.Count} Index: {@event.Index}");
}
}
private static async Task<StorageFolder> PickFolderAsync()
{
var folderPicker = new FolderPicker
{
SuggestedStartLocation = PickerLocationId.Desktop,
ViewMode = PickerViewMode.Thumbnail
};
folderPicker.FileTypeFilter.Add("*");
var _pickedFolder = await folderPicker.PickSingleFolderAsync();
return _pickedFolder;
}
private void GridView_ItemClick(object sender, ItemClickEventArgs e)
{
if (e.ClickedItem is FileInformation fileInformation)
{
Information.Add(fileInformation.Name);
}
else
{
if (e.ClickedItem == null)
{
Information.Add("Null");
}
else
{
Information.Add(e.ClickedItem.ToString());
}
}
}
private async void AddFilesAppBarButton_Click(object sender, RoutedEventArgs e)
{
for (int i = 1; i <= 15000; i++)
{
await _folder.CreateFileAsync(i + ".txt", CreationCollisionOption.ReplaceExisting);
if (i % 250 == 0)
{
Information.Add(i.ToString());
}
}
}
private async void ViewAllAppBarButton_Click(object sender, RoutedEventArgs e)
{
if (_folder == null)
{
Information.Add("Choose folder first");
return;
}
var state = await _folder.GetIndexedStateAsync();
var queryOptions = new QueryOptions { FolderDepth = FolderDepth.Deep, IndexerOption = IndexerOption.UseIndexerWhenAvailable };
Information.Add($"{_folder.Name} is {state} {queryOptions.IndexerOption}");
_query = _folder.CreateFileQueryWithOptions(queryOptions);
var st = Stopwatch.StartNew();
var numOfFiles = (await _query.GetItemCountAsync());
st.Stop();
Information.Add($"{state} {queryOptions.IndexerOption}. Found {numOfFiles} in {st.ElapsedMilliseconds / 1000.0}");
if (numOfFiles==0)
{
Information.Add("Generate files by clicking the Add button");
return;
}
_fileInformationFactory = new FileInformationFactory(_query, ThumbnailMode.SingleItem, Constants.Thumbnail_Size,
ThumbnailOptions.UseCurrentScale, delayLoad: false);
_vector = _fileInformationFactory.GetVirtualizedFilesVector();
CollectionViewSource.Source = _vector;
ItemCollectionView = CollectionViewSource.View;
_query.ContentsChanged += Query_ContentsChanged;
CollectionViewSource.View.VectorChanged += View_VectorChanged;
}
}
For Constants.Thumbnail_Size
, set it to e.g. 100.
Addendum
The problem is independent of an external hard drive. I created a partition on a modern Thinkpad X1 Yoga 3rd Gen which is not indexed. The issue is reproduced.
来源:https://stackoverflow.com/questions/58978986/gridview-looses-track-of-items-in-a-notindexed-location-and-many-do-not-get-disp