Как получить выбранные элементы из GridView - PullRequest
0 голосов
/ 28 сентября 2018

Я делаю программное обеспечение для управления библиотекой.Это XAML:

<CommandBar Grid.Row="0">
        <AppBarButton Icon="Add" 
                      Label="New Book"
                      Click="NewBook_Click"/>

        <AppBarButton Icon="Delete"
                      Label="Remove a Book"
                      Click="DeleteBook_Click"/>
    </CommandBar>

    <GridView x:Name="AllBooks_GridView"
              ItemsSource="{x:Bind Path=ViewModel.Books, Mode=OneWay}"
              ScrollViewer.VerticalScrollBarVisibility="Visible"
              ScrollViewer.VerticalScrollMode="Enabled"
              ScrollViewer.HorizontalScrollMode="Disabled"
              Grid.Row="1"
              SelectionMode="Multiple">

        <GridView.ItemTemplate>
            <DataTemplate x:DataType="data:Book">

                <StackPanel Margin="10" HorizontalAlignment="Center">
                    <Image Width="200" Height="200" Source="{x:Bind Path=CoverImageLocation, Mode=OneWay}" />
                    <Grid HorizontalAlignment="Stretch">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition />
                            <ColumnDefinition Width="Auto"/>
                        </Grid.ColumnDefinitions>
                        <StackPanel>
                            <TextBlock FontSize="16" 
                                       Text="{x:Bind Path=Title, Mode=OneWay}" 
                                       TextTrimming="WordEllipsis"/>
                            <TextBlock FontSize="10" 
                                       Text="{x:Bind Path=Author, Mode=OneWay}" 
                                       Margin="0, 3, 0, 0" 
                                       TextTrimming="WordEllipsis"/>
                        </StackPanel>
                        <TextBlock FontSize="20" 
                                   Text="{x:Bind Path=Quantity, Mode=OneWay}"
                                   Grid.Column="1" 
                                   VerticalAlignment="Bottom"                                        
                                   Margin="20, 0, 0, 0"
                                   HorizontalAlignment="Left"/>
                    </Grid>
                </StackPanel>

            </DataTemplate>
        </GridView.ItemTemplate>

    </GridView>

Я хочу выбрать несколько панелей и удалить их при нажатии второй кнопки панели приложения.Это функция DeleteBook_Click:

private void DeleteBook_Click(object sender, RoutedEventArgs e)
{
   var books = AllBooks_GridView.SelectedItems;

   foreach (var b in books)
   {
      var book = b as Book;

      DataAccess.DeleteBook(book.Title);
      ViewModel.Books.Remove(book);
   }
}

Это скриншот моего приложения:

enter image description here

Когда я нажимаю значок удаленияТолько первая книга удалена.Хотя оба они выбраны.Что я делаю не так?

Ответы [ 3 ]

0 голосов
/ 28 сентября 2018

Причина указана в ответе Kennyzx .

Чтобы заставить его работать правильно, сделайте что-то вроде этого:

private void DeleteBook_Click(object sender, RoutedEventArgs e)
{
   var books = AllBooks_GridView.SelectedItems.ToList(); // this will create a new list

   foreach (var b in books)
   {
      var book = b as Book;

      DataAccess.DeleteBook(book.Title);
      ViewModel.Books.Remove(book);
   }
}
0 голосов
/ 28 сентября 2018

Когда вы удаляете книгу из коллекции Books, ObservableCollection уведомит привязку данных об изменении, что, в свою очередь, изменит коллекцию SelectedItems.

Обычно это вызываетисключение, но в данном случае это не так, поскольку он «маскируется» тем, что удаление первого элемента просто перемещает второй элемент на его место (уменьшение размера коллекции), а перечисление вперед просто проверяет, существует ли следующий индекс,и поскольку это не так, цикл не продолжается.Вы можете подтвердить это, выбрав три элемента - первый будет удален, второй пропущен, а третий будет удален снова.

Самое простое решение - убедиться, чтоперебрать коллекцию, отличную от свойства SelectedItems.Самый дешевый способ добиться этого - использовать расширение LINQ ToArray в первой строке.

var books = AllBooks_GridView.SelectedItems.ToArray();

Это создаст новый массив, который будет содержать все книги, которые были выбраны, и когда вы затем удалите из ViewModel.Books и обновляет SelectedItems, это больше не будет иметь значения, поскольку наша books переменная является другим экземпляром.

0 голосов
/ 28 сентября 2018

Вы изменяете коллекцию во время итерации по ее элементам.

AllBooks_GridView.SelectedItems - это коллекция, а когда вы перебираете ее в цикле foreach, вы меняете ее, вызывая

ViewModel.Books.Remove(book);

После этого вызова GridView обновляется, чтобы отразить внесенные вами изменения в ViewModel, и количество элементов в коллекции SelectedItems уменьшается.И на следующей итерации SelectedItems больше не содержит двух книг, как вы, возможно, ожидали, а содержит только одну.И поскольку код пытается удалить вторую книгу из коллекции на следующей итерации, ничего не происходит, и цикл завершается.

Вот исправление:

//Now the books collection is no longer bound to the SelecteItems of the GridView, 
//it is 'immutable' in the foreach loop
List<Book> books = new List<Book>(); 
foreach (var item in AllBooks_GridView.SelectedItems)
    books.Add(item as Book); 

foreach (var book in books)
{
   DataAccess.DeleteBook(book.Title);
   ViewModel.Books.Remove(book);
}
...