【问题标题】:ListView CheckBox data binding - remove checked itemsListView CheckBox 数据绑定 - 删除选中项
【发布时间】:2018-01-09 17:43:07
【问题描述】:

当我单击删除按钮时,我试图删除列表视图中的所有选中项目。

我在很多地方看到IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected" 被提及,但我不知道应该如何将它与我的 IsChecked 绑定结合起来。

在我的代码中,这是抛出异常: lvStores.Items.Remove(item);

我正在导入具有以下结构的 CSV 文件:
"ID","NAME",CheckedINT
例如
"1662","BØRSTER",0 "1658","BØRSTER",1

我正在使用它以另一种方法循环遍历 ListView 中的数据:

    // Loop through ListView
    foreach (var item in lvStores.Items.OfType<Store>())
    {
        // If 1 item in Listview is checked then
        if (item.IsChecked == true)
        {
            blnOk = true;
            return;
        }
    }

XAML

<Window x:Class="CloneMacro.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:CloneMacro"
        mc:Ignorable="d"
        Title="Clone Macro" Height="348" Width="620.045" Closed="MainWindow_Closed" Icon="C:\Users\Niclas VMWare\Documents\Visual Studio 2015\Projects\CloneMacro\CloneMacro\images\copy.png">
    <Grid Background="#FFDEDEDE" Margin="-1,0,-8,0" HorizontalAlignment="Left" Width="621">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Button x:Name="cmdNew" HorizontalAlignment="Left" Margin="39,36,0,0" VerticalAlignment="Top" Width="39" Height="40" ToolTip="New" Click="cmdNew_Click">
            <Image x:Name="imgNew" HorizontalAlignment="Left" Height="37" VerticalAlignment="Top" Width="36" Source="C:\Users\Niclas VMWare\Documents\Visual Studio 2015\Projects\CloneMacro\CloneMacro\images\Generic_Document.png" RenderTransformOrigin="0.172,1.089"/>
        </Button>
        <Button x:Name="cmdOpen" HorizontalAlignment="Left" Margin="80,36,0,0" VerticalAlignment="Top" Width="39" Height="40" ToolTip="Open" Click="cmdOpen_Click">
            <Image x:Name="imgOpen" HorizontalAlignment="Left" Height="37" VerticalAlignment="Top" Width="36" Source="C:\Users\Niclas VMWare\Documents\Visual Studio 2015\Projects\CloneMacro\CloneMacro\images\folder_Open_32xLG.png"/>
        </Button>
        <Button x:Name="cmdSave" HorizontalAlignment="Left" Margin="121,36,0,0" VerticalAlignment="Top" Width="39" Height="40" ToolTip="Save" Click="cmdSave_Click">
            <Image x:Name="imgSave" HorizontalAlignment="Left" Height="37" VerticalAlignment="Top" Width="36" Source="C:\Users\Niclas VMWare\Documents\Visual Studio 2015\Projects\CloneMacro\CloneMacro\images\save_16xLG.png"/>
        </Button>
        <Button x:Name="cmdDelete" HorizontalAlignment="Left" Margin="235,36,0,0" VerticalAlignment="Top" Width="39" Height="40" Click="cmdDelete_Click">
            <Image x:Name="imgDelete" HorizontalAlignment="Left" Height="33" VerticalAlignment="Top" Width="32" Source="C:\Users\Niclas VMWare\Documents\Visual Studio 2015\Projects\CloneMacro\CloneMacro\images\action_Cancel_16xLG.png" ToolTip="Delete" RenderTransformOrigin="1.334,0.534"/>
        </Button>
        <Button x:Name="cmdNewStore" HorizontalAlignment="Left" Margin="275,36,0,0" VerticalAlignment="Top" Width="39" Height="40" Click="cmdNewStore_Click">
            <Image x:Name="imgNewStore" HorizontalAlignment="Left" Height="37" VerticalAlignment="Top" Width="36" Source="C:\Users\Niclas VMWare\Documents\Visual Studio 2015\Projects\CloneMacro\CloneMacro\images\action_add_16xLG.png" ToolTip="Add New Store" RenderTransformOrigin="0.5,0.5"/>
        </Button>
        <Button x:Name="cmdExecute" HorizontalAlignment="Left" Margin="355,36,0,0" VerticalAlignment="Top" Width="39" Height="40" ToolTip="Execute" Click="cmdExecute_Click">
            <Image x:Name="image" HorizontalAlignment="Left" Height="37" VerticalAlignment="Top" Width="37" Source="C:\Users\Niclas VMWare\Documents\Visual Studio 2015\Projects\CloneMacro\CloneMacro\images\StatusAnnotations_Play_32xLG_color.png"/>
        </Button>
        <Button x:Name="cmdCancel" HorizontalAlignment="Left" Margin="395,36,0,0" VerticalAlignment="Top" Width="39" Height="40" ToolTip="Cancel" Click="cmdCancel_Click">
            <Image x:Name="imgCancel" HorizontalAlignment="Left" Height="37" VerticalAlignment="Top" Width="36" Source="C:\Users\Niclas VMWare\Documents\Visual Studio 2015\Projects\CloneMacro\CloneMacro\images\CancelApproval_32x32.png"/>
        </Button>
        <CheckBox x:Name="chOpenLastUsed" Content="Open Last Used File" Margin="456,48,0,0" VerticalAlignment="Top" Height="21" Width="147" HorizontalAlignment="Left"/>
        <ListView x:Name="lvStores" HorizontalAlignment="Left" Height="161" Margin="39,98,0,0" VerticalAlignment="Top" Width="466">
            <ListView.View>
                <GridView>
                    <GridView.Columns>
                        <GridViewColumn Header="ID" Width="Auto">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <CheckBox Content="{Binding sID}" IsChecked="{Binding IsChecked}"/>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="Name" Width="Auto" DisplayMemberBinding="{Binding Path=sName}"/>
                        <GridViewColumn Header="Import File" Width="Auto" DisplayMemberBinding="{Binding Path=sImportFile}"/>
                    </GridView.Columns>
                </GridView>
            </ListView.View>
        </ListView>
        <Label x:Name="lblProgress" x:FieldModifier="public" Content="Status Text" HorizontalAlignment="Left" Margin="40,264,0,0" VerticalAlignment="Top" Width="465" BorderThickness="1" BorderBrush="#FF7C7C7C"/>
        <Button x:Name="ComDialog" HorizontalAlignment="Left" Margin="533,152,0,0" VerticalAlignment="Top" Width="48" Height="51">
            <Image x:Name="imgComDialog" HorizontalAlignment="Left" Height="44" VerticalAlignment="Top" Width="48" Source="C:\Users\Niclas VMWare\Documents\Visual Studio 2015\Projects\CloneMacro\CloneMacro\images\DialogID_6220_32x.png"/>
        </Button>
    </Grid>
</Window>

CS

    public MainWindow()
    {
        // Leave this to show the UI
        InitializeComponent();

        lblProgress.Content = "";


        lvStores.ItemsSource = ReadCSV(@"C:\Users\Niclas VMWare\Downloads\TESTFILE.pcf");

    }

    // Fill ListView
    public class Store
    {
        public string sName { get; set; }
        public string sImportFile { get; set; }
        public string sID { get; set; }
        public bool IsChecked { get; set; }

        public Store(string id, string strName, string isChecked, string strImportFile)
        {
            sName = strName.Replace("\"","");
            sImportFile = Path.GetFileName(strImportFile);
            sID = id.Replace("\"","");

            // Convert isChecked to boolean
            // Do convertion outside the constructor to avoid any exception within
            int iBool = Convert.ToInt32(isChecked);

            switch (iBool)
            {
                case 0: IsChecked = false; break;
                case 1: IsChecked = true; break;
                default: throw new InvalidOperationException("Third value in PCF file must be 0 or 1!");
            }
        }
    }
    public IEnumerable<Store> ReadCSV(string fileName)
    {
        // Make sure the file extension is pcf
        string[] lines = File.ReadAllLines(Path.ChangeExtension(fileName, ".pcf").Replace("\"", ""), Encoding.GetEncoding(65001));

        // lines.Select allows to project each line as a Store
        // This will give an IEnumerable<Store> back.
        return lines.Select(line =>
        {
            string[] data = line.Split(',');
            // Return the store data
            // Return id, Name, isChecked (chkbox checked?), filename
            return new Store(data[0], data[1], data[2], fileName);
        });
    }
    // End Fill ListView

    private void cmdDelete_Click(object sender, RoutedEventArgs e)
    {
        // if selected
        foreach (var item in lvStores.Items.OfType<Store>())
        {
            if (item.IsChecked == true)
            {
                lvStores.Items.Remove(item);
            }
        }
    }

【问题讨论】:

  • IsChecked 绑定没有意义的原因是因为您没有关注 MVVM。你真的应该在你的 WPF 解决方案中学习和实现它。完成后,您可以在 IsChecked viewmodel 属性上收听 PropertyChanged 并将其从 ObservableCollection 中删除
  • 抛出了哪个异常?
  • PresentationFramework.dll 中出现“System.InvalidOperationException”类型的异常,但未在用户代码中处理其他信息:使用 ItemsSource 时操作无效。改为使用 ItemsControl.ItemsSource 访问和修改元素。
  • @Yevgeniy 我应该在哪里删除这些项目?在 ReadCSV 方法中?你有示例代码吗?谢谢。s

标签: c# wpf listview checkbox data-binding


【解决方案1】:

我愿意:

  1. 使用 ObservableCollection
  2. 在您的设备上实施 INotifyPropertyChanged 存储类(或类似的东西……其他人正确地建议阅读 MVVM 范例)。这前两个是必要的,以确保您的 UI 在运行时更新对象。
  3. 遍历循环 颠倒顺序,并根据需要一次取出一件物品。

MainWindow.xaml:

<Window x:Class="CloneMacro.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:CloneMacro"
        mc:Ignorable="d"
        Title="Clone Macro" Height="348" Width="620.045">
    <Grid Background="#FFDEDEDE" Margin="-1,0,-8,0" HorizontalAlignment="Left" Width="621">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Button x:Name="cmdNew" HorizontalAlignment="Left" Margin="39,36,0,0" VerticalAlignment="Top" Width="39" Height="40" ToolTip="New" >
            New
        </Button>
        <Button x:Name="cmdOpen" HorizontalAlignment="Left" Margin="80,36,0,0" VerticalAlignment="Top" Width="39" Height="40" ToolTip="Open" Click="cmdOpen_Click">
            Open
        </Button>
        <Button x:Name="cmdSave" HorizontalAlignment="Left" Margin="121,36,0,0" VerticalAlignment="Top" Width="39" Height="40" ToolTip="Save">
            Save
        </Button>
        <Button x:Name="cmdDelete" HorizontalAlignment="Left" Margin="235,36,0,0" VerticalAlignment="Top" Width="39" Height="40" Click="cmdDelete_Click">
            Delete
        </Button>
        <Button x:Name="cmdNewStore" HorizontalAlignment="Left" Margin="275,36,0,0" VerticalAlignment="Top" Width="39" Height="40">
            New Store
        </Button>
        <Button x:Name="cmdExecute" HorizontalAlignment="Left" Margin="355,36,0,0" VerticalAlignment="Top" Width="39" Height="40" ToolTip="Execute">
            Execute
        </Button>
        <Button x:Name="cmdCancel" HorizontalAlignment="Left" Margin="395,36,0,0" VerticalAlignment="Top" Width="39" Height="40" ToolTip="Cancel">
            Cancel
        </Button>
        <CheckBox x:Name="chOpenLastUsed" Content="Open Last Used File" Margin="456,48,0,0" VerticalAlignment="Top" Height="21" Width="147" HorizontalAlignment="Left"/>
        <ListView x:Name="lvStores" HorizontalAlignment="Left" Height="161" Margin="39,98,0,0" VerticalAlignment="Top" Width="466">
            <ListView.View>
                <GridView>
                    <GridView.Columns>
                        <GridViewColumn Header="ID" Width="Auto">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <CheckBox Content="{Binding sID}" IsChecked="{Binding IsChecked}"/>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="Name" Width="Auto" DisplayMemberBinding="{Binding Path=sName}"/>
                        <GridViewColumn Header="Import File" Width="Auto" DisplayMemberBinding="{Binding Path=sImportFile}"/>
                    </GridView.Columns>
                </GridView>
            </ListView.View>
        </ListView>
        <Label x:Name="lblProgress" x:FieldModifier="public" Content="Status Text" HorizontalAlignment="Left" Margin="40,264,0,0" VerticalAlignment="Top" Width="465" BorderThickness="1" BorderBrush="#FF7C7C7C"/>
        <Button x:Name="ComDialog" HorizontalAlignment="Left" Margin="533,152,0,0" VerticalAlignment="Top" Width="48" Height="51">
            Dialog
        </Button>
    </Grid>
</Window>

MainWindow.xaml.cs:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace CloneMacro
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        ObservableCollection<Store> stores;

        internal const string TESTFILE = @"C:\Temp\TESTFILE.pcf";
        public MainWindow()
        {
            // Leave this to show the UI
            InitializeComponent();

            lblProgress.Content = "";

            OpenFile( TESTFILE );
        }

        internal void OpenFile( string fileName )
        {
            stores = ReadCSV( TESTFILE );
            lvStores.ItemsSource = stores;
        }

        // Fill ListView
        public class Store : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
            protected void OnPropertyChanged( string name )
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if ( handler != null )
                {
                    handler(this, new PropertyChangedEventArgs(name));
                }
            }

            public string sName { get; set; }
            public string sImportFile { get; set; }
            public string sID { get; set; }

            private bool isChecked;
            public bool IsChecked
            {
                get { return isChecked; }
                set
                {
                    if ( isChecked != value )
                    {
                        isChecked = value;
                        OnPropertyChanged("IsChecked");
                    }
                }
            }

            public Store( string id, string strName, string isChecked, string strImportFile )
            {
                sName = strName.Replace("\"", "");
                sImportFile = System.IO.Path.GetFileName(strImportFile);
                sID = id.Replace("\"", "");

                // Convert isChecked to boolean
                // Do convertion outside the constructor to avoid any exception within
                int iBool = Convert.ToInt32(isChecked);

                switch ( iBool )
                {
                    case 0: IsChecked = false; break;
                    case 1: IsChecked = true; break;
                    default: throw new InvalidOperationException("Third value in PCF file must be 0 or 1!");
                }
            }
        }

        public ObservableCollection<Store> ReadCSV( string fileName )
        {
            // Make sure the file extension is pcf
            string [] lines = File.ReadAllLines(
                System.IO.Path.ChangeExtension(fileName, ".pcf").Replace("\"", ""), Encoding.GetEncoding(65001));

            // lines.Select allows to project each line as a Store
            // This will give an IEnumerable<Store> back.
            var enumerable = lines.Select(line =>
            {
                string [] data = line.Split(',');
                // Return the store data
                // Return id, Name, isChecked (chkbox checked?), filename
                return new Store(data [0], data [1], data [2], fileName);
            });

            stores = new ObservableCollection<Store>();
            foreach ( var item in enumerable )
            {
                stores.Add( item );
            }
            return stores;
        }
        // End Fill ListView

        private void cmdDelete_Click( object sender, RoutedEventArgs e )
        {
            for ( int i = stores.Count - 1; i >= 0; i-- )
            {
                if ( stores[i].IsChecked )
                {
                    stores.RemoveAt( i );
                }
            }
        }

        private void cmdOpen_Click( object sender, RoutedEventArgs e )
        {
            OpenFile( TESTFILE );
        }

    }
}

TESTFILE.pcf:

"1662","BØRSTER",0
"1658","BØRSTER",1
"1669","A Møøse once bit my sister.",1

【讨论】:

  • 谢谢,它工作得很好。您没有更改 XAML 中的任何内容吗?你介意在你的代码中加入一些 cmets 吗?我将开始阅读 MVVM :-)
  • @Niclas 这是满足您要求的正确方法。我将删除我的答案,因为它不适用。
  • @Niclas,我并没有真正从您发布的代码中更改 XAML,除了删除您机器路径本地的一些图像文件。至于代码中的 cmets ......这将花费额外的费用。 :) 如果您对任何事情有任何具体问题,请提出。
猜你喜欢
  • 1970-01-01
  • 2021-06-08
  • 1970-01-01
  • 2011-06-05
  • 2018-11-01
  • 2010-12-03
  • 1970-01-01
  • 2012-07-28
  • 1970-01-01
相关资源
最近更新 更多