【问题标题】:How to remove checked items from a listbox in WPF?如何从 WPF 中的列表框中删除选中的项目?
【发布时间】:2013-01-16 21:10:12
【问题描述】:

我一直在开发一个清单应用程序,我正在使用ListBox 来显示数据。 我正在使用数组根据用户按下的按钮填充ListBox。 (我不知道这是否是最佳做法,但它现在有效。)用户完成这些步骤后,他可以使用以下命令删除项目:

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

问题是今天我学会了如何使用下面的 xaml 将CheckBoxes 添加到我的ItemTemplate

<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 中,显然这种方法不起作用,我只是不知道为什么。

【问题讨论】:

    标签: c# wpf list itemtemplate


    【解决方案1】:

    您可以将复选框绑定到 ListBoxItem 的 IsSelected 属性

    <DataTemplate>
        <CheckBox Content="{Binding .}" IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected" />
    </DataTemplate>
    

    【讨论】:

    • 谢谢穆斯塔法,这确实按预期工作。这确实是我现在拥有的更优雅的解决方案。我对使用这个解决方案犹豫不决,因为它从实际盒子和内容中删除了我的填充。此外,将来我还计划在该堆栈面板中添加按钮。
    【解决方案2】:

    对您的数据使用包装器,其中将包含特定于视图的数据,例如 IsChecked 属性。将属性绑定到CheckBox,然后就可以找到所有被勾选的项目了……

    简单示例:

    public class CheckedItem<T> where T : class
    {
        public T Data { get; set; }
        public bool IsChecked { get; set; }
    }
    

    因此,您创建的不是MyItem 列表,而是CheckedItem&lt;MyItem&gt; 列表

    不只是相应地更改绑定:

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

    【讨论】:

    • 很好的解决方案。我想提一下,OP 对此最重要的认识是 UI 不是 Data,因此他不应该期望从 UI 本身获取选择状态,而是从 Data 项中获取。
    【解决方案3】:

    您可以为您的项目创建一个 Model 并带有 Checked 属性,这样如果您更改 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>
    

    【讨论】:

      【解决方案4】:
       private void RemoveButton_Click(object sender, RoutedEventArgs e)
        {   
         foreach(CheckedItem in lstToDo.SelectedItems)
        {
          (lsttoDo.ItemsSource as List).Remove(CheckedItem);
        }
          lsttoDo.Items.Refresh();
       }
      

      在你的c#

      【讨论】:

      • 谢谢瑞秋,这是我想使用的解决方案,但它给了我一个错误。 "名称 configSetListBox 在当前上下文中不存在。我必须在其他地方声明吗?
      • 谢谢,这是我尝试的第一件事,但后来我得到了这个:找不到类型或命名空间名称“ConfigSet”(您是否缺少 using 指令或程序集引用?)需要在某处添加参考?我在 Google 上找不到任何信息。
      猜你喜欢
      • 1970-01-01
      • 2017-06-18
      • 1970-01-01
      • 2012-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多