FileInformationFactory GetVirtualizedItemsVector() does not update the file path when folder name is changed in UWP

ⅰ亾dé卋堺 提交于 2020-01-25 00:13:10

问题


I am using for a UWP app the FileInformationFactory to retrieve Virtualized vector of Items, which can be either a folder or a file information. I query the following folder structure on my desktop:

F0/F1/File1.png

Hence, I have a folder F0, which includes a folder F1 and the latter has a file File1.png. I set the IndexerOption.DoNotUseIndexer (code below), and that is at the origin of the issue. I need to use this option such that I can scan non-indexed USB drives.

The result of the query is displayed in a XAML GridView, and I display the Path of each item returned by the query, namely F1 and File1.png.

I do the following:

-Run the app

-Pick folder F0 which then displays the paths F1 and F1\File1.png (prefixed by C:\Users\xxxxx\Desktop\)

-I Open File Explorer and rename the folder F1 to F1a. The XAML view is reflected instantly as F1a and F1\File1.png.

This means that the path info is properly propagated to the folder F1, but the path of the file in F1, file being now in F1a, is not updated; it remains F1\File1.png.

That is not what I expected, because I expect that the change in name of folder F1 will propagate the results to all the files and folders it contains, hence the path for File1.png should be F1a\File1.png

Notice that if, now, I change the name of File1.png to File1a.png the view updates the result to the correct path for this file F1a\File1a.png.

Question: How to inform the view that a change in the folder name should also trigger a change in the path of the files and folders in this folder??

Notice that the Photos app from Microsoft suffers from the same problem.

Notice, too, that I checked out the various events of the CollectionViewSource and item query, without success as these are not specific about the kind of change which occurred. The only solution is to refresh the whole view with brute force, but that becomes very difficult to the user beyond a certain number of items.

Besides the fact that I am pretty sure that the current behavior is inconsistent, I hope someone could help, either confirm/reject that this is a limitation of the API or and above all point to a solution. Thank you, here is the code which should run on its own (for Constants.Thumbnail_Size set e.g. 96).

<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"
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="*"/>
        <ColumnDefinition Width="48"/>
    </Grid.ColumnDefinitions>
    <StackPanel Grid.ColumnSpan="1" Orientation="Horizontal"
                BorderBrush="{ThemeResource ApplicationBorderBrush}" BorderThickness="0,0,2,2">
        <AppBarButton x:Name="FolderPickerButton" Icon="Folder"
                      LabelPosition="Collapsed" Label="Select Folder"
                      Click="FolderPickerButton_Click"/>
        <AppBarSeparator/>
    </StackPanel>
    <GridView Grid.Row="1" Grid.Column="1"
              ItemsSource="{x:Bind ItemCollectionView, Mode=OneWay}" IsItemClickEnabled="True">
        <GridView.ItemTemplate>
            <DataTemplate x:DataType="ba:IStorageItemInformation">
                    <TextBlock Text="{Binding Path}" TextWrapping="WrapWholeWords"/>
            </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;
    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)
        {
            return;
        }
        _folder = _pickedFolder;

        var queryOptions = new QueryOptions { FolderDepth = FolderDepth.Deep, IndexerOption = IndexerOption.DoNotUseIndexer };

        _query = _folder.CreateItemQueryWithOptions(queryOptions);

        var _fileInformationFactory = new FileInformationFactory(_query, ThumbnailMode.SingleItem, Constants.Thumbnail_Size,
           ThumbnailOptions.UseCurrentScale, delayLoad: false);

        var _vector = _fileInformationFactory.GetVirtualizedItemsVector();
        CollectionViewSource.Source = _vector;

        ItemCollectionView = CollectionViewSource.View;
        _query.ContentsChanged += Query_ContentsChanged;
        CollectionViewSource.View.VectorChanged += View_VectorChanged; ;
    }

    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)
    {
        Information.Add($"Vector Changed {@event.CollectionChange} 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;
    }
}

Edit

Additionally, there is another unexpected behavior to say the least. If you delete the folder F1 (or F1a if you renamed it so), the view is not updated. But deleting the file inside this folder will update the view. This is unfortunate as, unless I missed a point, it makes the API not so reliable.

来源:https://stackoverflow.com/questions/58939388/fileinformationfactory-getvirtualizeditemsvector-does-not-update-the-file-path

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