【问题标题】:How to get selected items from a GridView如何从 GridView 中获取选定的项目
【发布时间】:2018-09-28 04:45:23
【问题描述】:

我正在制作图书馆管理软件。这是 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);
   }
}

这是我的应用程序的屏幕截图:

当我点击删除图标时,只有第一本书被删除。虽然这两个都被选中了。我做错了什么?

【问题讨论】:

  • foreach 循环是否运行两次? SelectedItems 集合是否包含两个条目?你能在方法中放置一个断点并单步执行代码吗?我怀疑当您从Books 集合中删除这本书时,数据绑定会导致重新加载和SelectedItems 更改。虽然我希望这会导致 foreach 循环中的异常。
  • 另外,激活 Windows ;-)
  • @MartinZikmund 我刚刚调试了代码,有趣的是它并没有引发典型的“在迭代时修改集合”异常,它只是继续处理已经更改的集合。因此,如果您收藏了 8 本书(全部选中),则单击将删除 4 本书,而其余 4 本书仍处于选中状态。
  • @MartinZikmund,我希望我可以。问题是我属于印度中产阶级家庭。我的笔记本电脑花了我 30k 的本国货币。而在印度,Win 10 pro 的价格是 15k。我负担不起。 :(
  • 另外,我是一名学生。当我自己挣钱时,我会用合法的 Win 10 @MartinZikmund 构建我的电脑

标签: xaml uwp uwp-xaml


【解决方案1】:

您在迭代其项目时​​正在更改集合。

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

【讨论】:

    【解决方案2】:

    当您从Books 集合中删除一本书时,ObservableCollection 将通知数据绑定有关更改,进而修改SelectedItems 集合。

    通常,这会引发异常,但在这种情况下,不会因为删除第一项只会将第二项移动到其位置(降低集合的大小)并向前枚举而被“掩盖”只是检查下一个索引是否存在,因为它不存在,所以循环不会继续。您可以通过选择三个项目来确认这一点 - 第一个将被删除,第二个将被跳过,但第三个将被再次删除。

    最简单的解决方案是确保迭代与SelectedItems 属性不同的集合。实现这一点最便宜的方法是在第一行使用 LINQ ToArray 扩展。

    var books = AllBooks_GridView.SelectedItems.ToArray();
    

    这将创建一个新数组,其中包含所有被选中的书籍,然后当您从 ViewModel.Books 中删除并更新 SelectedItems 时,这将不再重要,因为我们的 books 变量是 不同的实例。

    【讨论】:

      【解决方案3】:

      原因在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);
         }
      }
      

      【讨论】:

        猜你喜欢
        • 2016-03-16
        • 1970-01-01
        • 1970-01-01
        • 2011-09-15
        • 1970-01-01
        • 1970-01-01
        • 2012-06-01
        • 1970-01-01
        • 2018-06-21
        相关资源
        最近更新 更多