使用 ListView 的 WinRT ObservableCollection 删除操作

WinRT ObservableCollection delete operation with ListView

我正在开发一个 WinRT 8.1 应用程序,我在其中将 ListView 控件绑定到 ObservableCollection,如此

            <ListView x:Name="DetailsViews" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Row="3" Width="395">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Grid x:Name="grid" Holding="grid_Holding" Height="60" Width="395">
                        <FlyoutBase.AttachedFlyout>
                            <MenuFlyout>
                                <MenuFlyoutItem x:Name="DeleteButton" Text="delete" Click="DeleteSelectedItem"/>
                            </MenuFlyout>
                        </FlyoutBase.AttachedFlyout>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="70"/>
                            <ColumnDefinition Width="1*"/>
                            <ColumnDefinition Width="40"/>
                        </Grid.ColumnDefinitions>
                        <TextBlock HorizontalAlignment="Center" FontSize="32" TextAlignment="Center" Text="{Binding DetailTitle}" VerticalAlignment="Center"/>
                        <TextBox HorizontalAlignment="Left" FontSize="32" Height="{Binding ElementName=grid, Path=Height}" Text="{Binding DetailValue}" TextWrapping="Wrap" VerticalAlignment="Center" Grid.Column="1" Width="320"/>
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

这是我的代码隐藏文件。

myList = new ObservableCollection<Person>();

myList.Add(new Person() { DetailTitle = "Key", DetailValue = "Value"  });

DetailsViews.ItemsSource = myList;

我需要知道如何从 ObservableCollection 中删除项目,以便在每次删除时更新 UI。这是我的删除代码,但它不起作用,因为如果我在那里放置断点,SelectedIndex 每次都会返回 -1。

private void DeleteSelectedItem(object sender, RoutedEventArgs e)
{
    this.myList.RemoveAt(this.DetailsViews.SelectedIndex);
}

如何更新 UI 以及可能出现的问题?

好的,这是我能想到的最基本的示例,使用基本的空模板,它可以工作,这就是为什么@KooKiz 说您的代码看起来不错。

因此,您至少需要 post 声明 ListView 的部分才能获得解决问题的帮助。

Xaml

<Page
    x:Class="App1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <ListView Name="ItemsView" ItemsSource="{Binding items}"/>
        <Button Click="Button_Click" Content="Test Remove"></Button>
    </Grid>
</Page>

代码隐藏

using System;
using System.Collections.ObjectModel;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace App1
{
    public sealed partial class MainPage : Page
    {
        ObservableCollection<String> items = new ObservableCollection<string>();

        public MainPage()
        {
            this.InitializeComponent();

            items.Add("First Item");
            items.Add("Second Item");
            items.Add("Third Item");
            items.Add("Fourth Item");

            ItemsView.ItemsSource = items;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            items.RemoveAt(ItemsView.SelectedIndex);
        }
    }
}

编辑

好的,感谢您更新了代码,我能够找出问题所在,我为您提供了一个快速解决方案,如果不完全正确,我还会提供一些建议你想从中得到什么:)

说明

我想你有一个处理持有事件的方法是这样的:

private void grid_Holding(object sender, Windows.UI.Xaml.Input.HoldingRoutedEventArgs e)
{
    FlyoutBase.ShowAttachedFlyout(sender as FrameworkElement);
}

所以发生的事情是 你在用手指按住时触发了 holding 事件,但这个事件不会 select 任何项目,因为项目是 selected on touches/clicks,这就是为什么当您单击删除时它没有 selected 元素。

我已经测试了 select 一个单点触摸的项目,然后做握持部分,它工作正常。

解决方法

现在我们知道发生了什么,有不同的解决方案,具体取决于您最终想要实现的目标,为简单起见,我将假设最容易实现的:)。

假设您不以任何其他方式使用 selected 项目而不是删除它们或导航(不需要 selection 列表视图项目)

所以首先我们将XAML中的ListView编辑为SelectionMode="None" (请注意,给定的修复程序在没有它的情况下仍然有效,但它可能会使用户感到困惑)

<ListView x:Name="DetailsViews" 
          SelectionMode="None"
          HorizontalAlignment="Center"
          VerticalAlignment="Top" 
          Grid.Row="3" 
          Width="395">

那么你需要在代码后面添加一个 属性 来保存 selected 项目的值,因为你不会使用 selection (index或项目)的 ListView。

public Person SelectedItem { get; set; }

然后我们需要稍微修改删除和保留处理程序以使用新的 属性

private void DeleteSelectedItem(object sender, RoutedEventArgs e)
{
    //items.RemoveAt(DetailsViews.SelectedIndex);
    items.Remove(SelectedItem);
}

private void grid_Holding(object sender, Windows.UI.Xaml.Input.HoldingRoutedEventArgs e)
{
    SelectedItem = (sender as FrameworkElement).DataContext as Person;
    FlyoutBase.ShowAttachedFlyout(sender as FrameworkElement);
}

所以这些现在做的是:删除项目现在通过对象而不是索引删除

并且该对象来自持有处理程序,您在其中将 selected 项设置为当前按下的元素的 DataContext(即 ListView 元素的 DataContext,即 Person)

我建议您添加一些防御性编程并进行一些检查以保护您的程序免受 crashes/exceptions 的攻击。如果您正在做测试项目以外的任何事情,我还建议您学习一些关于如何使用 MVVM 的课程。

干杯,编码愉快 ;)