GridView looses track of items in a NotIndexed location and many do not get displayed anymore

半城伤御伤魂 提交于 2020-01-16 08:53:14

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!