简体   繁体   English

与 StorageFile.RenameAsync() 相比,FileInformation.RenameAsync() 打破了绑定

[英]FileInformation.RenameAsync() breaks binding compared to StorageFile.RenameAsync()

What makes the following code break the binding of a FileInformation DataTemplate of a ListView when the clicked item is renamed?当单击的项目重命名时,是什么使以下代码破坏了ListViewFileInformation DataTemplate的绑定? And then, how to get the proper notification to the view that the FileInformation has been renamed?然后,如何获得FileInformation已重命名的视图的正确通知?

Consider a folder with 2 images, 1.jpg and 2.jpg.考虑一个包含 2 个图像的文件夹,1.jpg 和 2.jpg。 This folder is indexed by Windows 10 1909 and the UWP app is version 1903.此文件夹由 Windows 10 1909 编制索引,UWP 应用程序版本为 1903。

After the user selected a folder, we create a FileInformationFactory and retrieve the VirtualizedFiles object and set it to the source of CollectionViewSource .在用户选择一个文件夹后,我们创建一个FileInformationFactory并检索VirtualizedFiles对象并将其设置为CollectionViewSource的源。 The view of the latter populates an ICollectionView which is OneWay bound to the ItemsSource of a ListView.后者的视图填充一个ICollectionView ,它是 OneWay 绑定到 ListView 的 ItemsSource。

We display in the listview each file Name and file FolderRelativeId of the FileInformation .我们在列表视图中显示FileInformation每个文件Name和文件FolderRelativeId A rename button takes the ListView.Selecteditem and renames it as 1.jpg, with the option of GenerateUniqueName .重命名按钮采用 ListView.Selecteditem 并将其重命名为 1.jpg,并带有GenerateUniqueName选项。

There are two methods at hand.手头有两种方法。

1) The most natural one given the code is to use FileInformation.RenameAsync() , since the selected item already is a FileInformation . 1) 给定代码最自然的方法是使用FileInformation.RenameAsync() ,因为所选项目已经是FileInformation

2) Get the Storagefile from folder.GetFileAsync, where the name parameter is given by the FileInformation.Name, and then call the StorageFile.RenameAsync. 2)从folder.GetFileAsync中获取Storagefile,其中name参数由FileInformation.Name给出,然后调用StorageFile.RenameAsync。

In both methods, as we rename the file, the listview is updated, as expected.在这两种方法中,当我们重命名文件时,列表视图会按预期更新。 However, this does not last long as I keep renaming, even if I give the time for the file to be renamed.然而,这不会持续很长时间,因为我不断重命名,即使我给文件重命名的时间。 Indeed, in the first scenario I can rename the file, but, as I keep renaming , at some unclear point, the listview seems stuck to the previous renamed name and mismatches the FolderRelativeId .确实,在第一种情况下,我可以重命名文件,但是,随着我不断重命名,在某些不清楚的地方,列表视图似乎停留在先前重命名的名称上,并且与FolderRelativeId不匹配。 For instance, the name of the file appears as "1 (2).jpg" while FoldeRelativeId ends with "1 (3).jpg.jpg".例如,文件名显示为“1 (2).jpg”,而 FolderRelativeId 以“1 (3).jpg.jpg”结尾。 The listview does not recognize the item as part of the ListView as I cannot select it anymore and renaming throws a caught exception. listview 无法将该项目识别为 ListView 的一部分,因为我无法再选择它并且重命名会引发捕获的异常。

This problem does not seem to appear in scenario 2, why?这个问题在场景2中好像没有出现,为什么? How can I use scenario 1 (ie stick to FileInformation for renaming) and keep notifications alive to update the UI without this bug?如何使用场景 1(即坚持使用FileInformation进行重命名)并保持通知活动以在没有此错误的情况下更新 UI?

An additional question would be how to keep the selected item the same after the file has been renamed, because often (not always!) the selected item is lost (index=-1), probably because the ICollectionview has been reset owing to notifications from the file system.另一个问题是如何在文件重命名后保持所选项目相同,因为经常(并非总是!)所选项目丢失(索引 = -1),可能是因为 ICollectionview 由于来自文件系统。

To see the bug, uncomment the line in the RenameButtonClick event (and comment the rename call from the storagefile a few lines above).要查看错误,请取消注释 RenameButtonClick 事件中的行(并注释上面几行存储文件中的重命名调用)。 await fileInformation.RenameAsync("1.jpg", NameCollisionOption.GenerateUniqueName);

Any help is appreciated as I am struggling on this issue since a few days now.任何帮助表示赞赏,因为我已经在这个问题上挣扎了几天。 Thanks谢谢

public sealed partial class Scenario5 : Page, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
      => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    public Scenario5()
    {
        this.InitializeComponent();
    }

    private ICollectionView _fileCollectionView;
    private StorageFolder _folder;
    private QueryOptions _queryOptions;
    private StorageFileQueryResult _query;
    private FileInformationFactory _fileInformationFactory;

    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;
        }
        Information.Clear();
        _folder = _pickedFolder;
        _queryOptions = new QueryOptions
        {
            FolderDepth = FolderDepth.Deep,
            IndexerOption = IndexerOption.UseIndexerWhenAvailable,
        };

        _query = _folder.CreateFileQueryWithOptions(_queryOptions);

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

        var _vector = _fileInformationFactory.GetVirtualizedFilesVector();

        CollectionViewSource.Source = _vector;
        ItemCollectionView = CollectionViewSource.View;


    }

    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 ListView_ItemClick(object sender, ItemClickEventArgs e)
    {
        if (e.ClickedItem is FileInformation fileInformation)
        {
            Information.Add($"Click {fileInformation.Name}\n{fileInformation.FolderRelativeId}");
        }
    }

    private async void RenameButton_Click(object sender, RoutedEventArgs e)
    {
        if (itemCollectionGridView.SelectedItem is FileInformation fileInformation)
        {
            Information.Add($"Selected item: {fileInformation.Name}\n{fileInformation.FolderRelativeId}");

            try
            {
                var storageFile = await _folder.GetFileAsync(fileInformation.Name);
                await storageFile.RenameAsync("1.jpg", NameCollisionOption.GenerateUniqueName);
                Information.Add($"Renamed storagefile {storageFile.Name}\n{storageFile.FolderRelativeId}");

                //await fileInformation.RenameAsync("1.jpg", NameCollisionOption.GenerateUniqueName);
                Information.Add($"Renamed FileInformation result {fileInformation.Name}\n{fileInformation.FolderRelativeId}");
            }
            catch (Exception ex)
            {
                Information.Add($"{ex.Message}\n" +
                    $"{fileInformation.Name}\n{fileInformation.FolderRelativeId}");
            }
        }
    }

    private void ClearButton_Click(object sender, RoutedEventArgs e)
    {
        Information.Clear();
    }
}

And the XAML和 XAML

<Page
x:Class="Virtualization.Scenario5"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Virtualization"
xmlns:ba="using:Windows.Storage.BulkAccess"    
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
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="Blue" BorderThickness="0,0,2,2">
        <AppBarButton Icon="Folder"
                      LabelPosition="Collapsed"
                      Click="FolderPickerButton_Click"/>
        <AppBarButton Icon="Rename"
                      LabelPosition="Collapsed"
                      Click="RenameButton_Click"/>
        <AppBarButton Icon="Clear"
                      LabelPosition="Collapsed" Label="Select Folder"
                      Click="ClearButton_Click"/>
    </StackPanel>
    <ListView x:Name="itemCollectionGridView" Grid.Row="1" Grid.Column="1"
              ItemsSource="{x:Bind ItemCollectionView, Mode=OneWay}" IsItemClickEnabled="True"
              ItemClick="ListView_ItemClick">
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="ba:FileInformation">
                <StackPanel MinHeight="100">
                    <TextBlock Text="{Binding Name}" TextWrapping="WrapWholeWords"/>
                    <TextBlock Text="{Binding Path}" TextWrapping="WrapWholeWords"/>
                    <TextBlock Text="{Binding FolderRelativeId}" TextWrapping="WrapWholeWords"/>

                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

    <ListView Grid.Row="1" Grid.Column="2" ItemsSource="{x:Bind Information, Mode=OneWay}">
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <ItemsStackPanel ItemsUpdatingScrollMode="KeepLastItemInView" />
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
        <ListView.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}"/>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

</Grid>

FileInformation.RenameAsync() breaks binding compared to StorageFile.RenameAsync()与 StorageFile.RenameAsync() 相比,FileInformation.RenameAsync() 打破了绑定

The problem looks like a bug and I could reproduce this issue, In general we often storageFile.RenameAsync method to rename the file.这个问题看起来像一个错误,我可以重现这个问题,通常我们经常使用storageFile.RenameAsync方法来重命名文件。 Please try to use storageFile.RenameAsync to replace, and you could report this with windows feed back hub app.请尝试使用 storageFile.RenameAsync 来替换,您可以使用 Windows 反馈中心应用程序报告此问题。

An additional question would be how to keep the selected item the same after the file has been renamed, because often (not always!) the selected item is lost (index=-1), probably because the ICollectionview has been reset owing to notifications from the file system.另一个问题是如何在文件重命名后保持所选项目相同,因为经常(并非总是!)所选项目丢失(索引 = -1),可能是因为 ICollectionview 由于来自文件系统。

It will take some time to build the new index for the file then notify the ICollectionview , the better way is add the folder to the FutureAccessList , and re-create the ICollectionview .为文件构建新索引需要一些时间,然后通知ICollectionview ,更好的方法是将文件夹添加到FutureAccessList ,并重新创建ICollectionview

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM