0

当单击的项目被重命名时,是什么使以下代码破坏了 a 的绑定 FileInformation DataTemplateListView然后,如何正确通知FileInformation已重命名的视图?

考虑一个包含 2 张图片、1.jpg 和 2.jpg 的文件夹。此文件夹由 Windows 10 1909 索引,UWP 应用为 1903 版。

用户选择文件夹后,我们创建FileInformationFactory并检索VirtualizedFiles对象并将其设置为CollectionViewSource. 后者的视图填充了一个ICollectionView绑定到 ListView 的 ItemsSource 的 OneWay。

我们在列表视图中显示每个文件Name和. 重命名按钮采用 ListView.Selecteditem 并将其重命名为 1.jpg,并带有 .jpg 选项。FolderRelativeIdFileInformationGenerateUniqueName

手头有两种方法。

1)给定代码最自然的一个是使用 FileInformation.RenameAsync(),因为所选项目已经是FileInformation

2)从folder.GetFileAsync中获取Storagefile,其中name参数由FileInformation.Name给出,然后调用StorageFile.RenameAsync。

在这两种方法中,当我们重命名文件时,列表视图会按预期更新。但是,这不会持续很长时间,因为我一直在重命名,即使我给了重命名文件的时间。确实,在第一种情况下,我可以重命名文件,但是,当我不断重命名时,在某些不清楚的地方,列表视图似乎坚持以前重命名的名称并且与FolderRelativeId. 例如,文件名显示为“1 (2).jpg”,而 FoldeRelativeId 以“1 (3).jpg.jpg”结尾。listview 无法将该项目识别为 ListView 的一部分,因为我无法再选择它并且重命名会引发捕获的异常。

这个问题在场景2中似乎没有出现,为什么?如何使用方案 1(即坚持FileInformation重命名)并保持通知活动以更新 UI 而不会出现此错误?

另一个问题是如何在文件重命名后保持所选项目相同,因为经常(并非总是!)所选项目丢失(索引=-1),可能是因为 ICollectionview 已因来自通知的通知而被重置文件系统。

要查看错误,请取消注释 RenameButtonClick 事件中的行(并在上面几行注释来自 storagefile 的重命名调用)。 await fileInformation.RenameAsync("1.jpg", NameCollisionOption.GenerateUniqueName);

感谢任何帮助,因为我几天以来一直在这个问题上苦苦挣扎。谢谢

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();
    }
}

和 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>

4

1 回答 1

1

FileInformation.RenameAsync() 与 StorageFile.RenameAsync() 相比会破坏绑定

这个问题看起来像一个错误,我可以重现这个问题,通常我们经常storageFile.RenameAsync重命名文件。请尝试使用 storageFile.RenameAsync 替换,您可以使用 Windows 反馈中心应用程序报告此问题。

另一个问题是如何在文件重命名后保持所选项目相同,因为经常(并非总是!)所选项目丢失(索引=-1),可能是因为 ICollectionview 已由于来自通知的通知而被重置文件系统。

为文件建立新索引需要一些时间然后通知ICollectionview,更好的方法是将文件夹添加到FutureAccessList,然后重新创建ICollectionview.

于 2020-01-14T06:53:18.153 回答