如何在WPF中从列表框中删除选中的项目?

3

我一直在开发一个清单应用程序,使用 ListBox 显示数据。根据用户按下的按钮,我使用数组填充 ListBox。(我不知道这是否是最佳实践,但现在它能够正常工作。)一旦用户完成了步骤,他可以使用以下命令删除项目:

private void SendSelected()
{
    while (lstToDo.SelectedItems.Count > 0)
    {
        lstToDo.Items.Remove(lstToDo.SelectedItem);
    }
}

问题在于我今天学习了如何使用以下xaml在我的ItemTemplate中添加CheckBox:
<ListBox.ItemTemplate>
    <DataTemplate>
        <StackPanel Orientation="Horizontal">
            <CheckBox Padding="10">                            
                <CheckBox.LayoutTransform>
                    <ScaleTransform ScaleX="1" ScaleY="1" />
                </CheckBox.LayoutTransform>
            </CheckBox>
            <TextBlock Text="{Binding}"/>
        </StackPanel>
    </DataTemplate>
</ListBox.ItemTemplate>

现在删除按钮仍然起作用... 但是我希望调整它,使其删除已选中的项目而不是选择的项目。 在winforms中,我曾经这样做:

while (lstToDo.CheckedItems.Count > 0)
{
    lstToDo.Items.Remove(lstToDo.CheckedItems[0]);
}  

但在WPF中,显然这种方法不起作用,我只是不确定原因。

4个回答

2
你可以将复选框绑定到ListBoxItem的IsSelected属性。
<DataTemplate>
    <CheckBox Content="{Binding .}" IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected" />
</DataTemplate>

谢谢你,Mustafa。这确实像预期的那样工作。这是比我现在拥有的更优雅的解决方案。虽然如此,我还是有些犹豫使用这个解决方案,因为它会移除我从实际框和内容中获得的填充。另外,在未来,我计划向该堆栈面板添加按钮。 - bolilloBorracho

0
使用一个数据包装器,其中包括视图特定的数据,例如IsChecked属性。将该属性绑定到CheckBox,然后您就可以找到所有已选中的项目...
简单示例:
public class CheckedItem<T> where T : class
{
    public T Data { get; set; }
    public bool IsChecked { get; set; }
}

所以,你可以创建一个 CheckedItem<MyItem> 的列表,而不是 MyItem 的列表。
只需相应地更改绑定即可:
<ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <CheckBox Padding="10" IsChecked={Binding IsChecked}>                            
                    <CheckBox.LayoutTransform>
                        <ScaleTransform ScaleX="1" ScaleY="1" />
                    </CheckBox.LayoutTransform>
                </CheckBox>
                <TextBlock Text="{Binding Data}"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>

如果你只想删除已选中的项目,可以像这样获取它们:

List<CheckedItem<MyItem>> MyItems; 
...
...

foreach (var Item in MyItems)
{
    if (!Item.IsChecked)
    {
         lstToDo.Items.Remove(Item);
    }
}

2
好的解决方案。我想提到,OP 需要意识到最重要的一点是 UI 不是数据,因此他不应该期望从 UI 本身获取选择状态,而是应该从数据项中获取。 - Federico Berasategui

0
 private void RemoveButton_Click(object sender, RoutedEventArgs e)
  {   
   foreach(CheckedItem in lstToDo.SelectedItems)
  {
    (lsttoDo.ItemsSource as List).Remove(CheckedItem);
  }
    lsttoDo.Items.Refresh();
 }

在你的中。

谢谢Rachel,这是我想要使用的解决方案,但它给了我一个错误。 “当前上下文中不存在configSetListBox名称。我需要在其他地方声明吗? - bolilloBorracho
谢谢,那是我尝试的第一件事,但是我得到了这个错误:找不到类型或命名空间名称“ConfigSet”(是否缺少使用指令或程序集引用?)我需要在哪里添加引用吗?我在Google上找不到任何信息。 - bolilloBorracho

0
你可以为你的项目创建一个带有Checked属性的Model,这样如果你在UI中更改数据,则MyList将被更新;如果你在代码中更新MyList中的项目,则UI将反映这些更改。
因此,如果你从MyList中删除所有已选项目,则它们将从ListBox中删除。
public partial class MainWindow : Window
{
    private ObservableCollection<MyObject> _myItems = new ObservableCollection<MyObject>();

    public MainWindow()
    {
        InitializeComponent();
        MyItems.Add(new MyObject { Name = "Test1" });
        MyItems.Add(new MyObject { Name = "Test2" });
        MyItems.Add(new MyObject { Name = "Test3" });
        MyItems.Add(new MyObject { Name = "Test4" });
    }

    public ObservableCollection<MyObject> MyItems
    {
        get { return _myItems; }
        set { _myItems = value; }
    }

    public void RemoveItems()
    {
        // Remove any items fro MyList that "IsChecked"
    }
}

public class MyObject : INotifyPropertyChanged
{
    private string _name;
    private bool _isChecked;

    public string Name
    {
        get { return _name; }
        set { _name = value; NotifyPropertyChanged("Name"); }
    }

    public bool IsChecked
    {
        get { return _isChecked; }
        set { _isChecked = value; NotifyPropertyChanged("IsChecked"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(string property)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }
}

xaml:

<Window x:Class="WpfApplication8.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="199" Width="206" Name="UI">
    <Grid DataContext="{Binding ElementName=UI}">
        <ListBox ItemsSource="{Binding MyItems}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <CheckBox Padding="10" IsChecked="{Binding IsChecked}">
                            <CheckBox.LayoutTransform>
                                <ScaleTransform ScaleX="1" ScaleY="1" />
                            </CheckBox.LayoutTransform>
                        </CheckBox>
                        <TextBlock Text="{Binding Name}"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接