FileInformation.RenameAsyn c () прерывает привязку по сравнению с StorageFile.RenameAsyn c () - PullRequest
0 голосов
/ 13 января 2020

Что заставляет следующий код нарушать привязку FileInformation DataTemplate к ListView, когда выбранный элемент переименовывается? А затем, как получить правильное уведомление о том, что FileInformation был переименован?

Рассмотрим папку с 2 изображениями, 1.jpg и 2.jpg. Эта папка индексируется Windows 10 1909, а приложение UWP - версия 1903.

После того, как пользователь выбрал папку, мы создаем FileInformationFactory, извлекаем объект VirtualizedFiles и устанавливаем его в качестве источника CollectionViewSource. Представление последнего заполняет ICollectionView, который OneWay связан с Источником Items ListView.

Мы отображаем в представлении списка каждый файл Name и файл FolderRelativeId из FileInformation. Кнопка переименования берет ListView.Selecteditem и переименовывает его в 1.jpg с опцией GenerateUniqueName.

. Есть два метода под рукой.

1) Самый естественный из приведенных код должен использовать FileInformation.RenameAsync(), поскольку выбранный элемент уже является FileInformation.

2) Получить файл хранилища из папки. GetFileAsyn c, где параметр имени задается в FileInformation.Name и затем вызовите StorageFile.RenameAsyn c.

. В обоих методах при переименовании файла представление списка обновляется, как и ожидалось. Однако это не длится долго, так как я продолжаю переименовывать, даже если я даю время для переименования файла. Действительно, в первом сценарии я могу переименовать файл, но, поскольку я продолжаю переименовывать, в какой-то непонятной точке список выглядит застрявшим в предыдущем переименованном имени и не соответствует FolderRelativeId. Например, имя файла отображается как «1 (2) .jpg», а FoldeRelativeId оканчивается на «1 (3) .jpg.jpg». Представление списка не распознает элемент как часть ListView, так как я больше не могу его выбрать, и переименование вызывает перехваченное исключение.

Эта проблема, похоже, не возникает в сценарии 2, почему? Как я могу использовать сценарий 1 (т. Е. Придерживаться FileInformation для переименования) и поддерживать уведомления в актуальном состоянии для обновления интерфейса без этой ошибки?

Еще один вопрос - как сохранить выбранный элемент таким же после файла был переименован, потому что часто (не всегда!) выбранный элемент теряется (индекс = -1), возможно, потому что ICollectionview был сброшен из-за уведомлений из файловой системы.

Чтобы увидеть ошибку, раскомментируйте строка в событии RenameButtonClick (и прокомментируйте вызов переименования из файла хранилища несколькими строками выше). 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>

1 Ответ

1 голос
/ 14 января 2020

FileInformation.RenameAsyn c () нарушает привязку по сравнению с StorageFile.RenameAsyn c ()

Проблема выглядит как ошибка, и я мог воспроизвести эту проблему. В общем мы часто storageFile.RenameAsync способ переименовать файл. Пожалуйста, попробуйте использовать storageFile.RenameAsyn c для замены, и вы можете сообщить об этом с помощью windows приложения центра обратной связи.

Еще один вопрос - как сохранить выбранный элемент таким же после файл был переименован, поскольку часто (не всегда!) выбранный элемент теряется (индекс = -1), возможно, из-за сброса ICollectionview из-за уведомлений из файловой системы.

It потребуется некоторое время, чтобы создать новый индекс для файла, затем уведомить ICollectionview, лучше добавить папку в FutureAccessList и заново создать ICollectionview.

...