【问题标题】:Loading Data into Listview (WPF)将数据加载到 Listview (WPF)
【发布时间】:2015-06-24 17:43:17
【问题描述】:

我正在尝试制作重复文件检测器(相关问题:Compare adjacent list items)。我的一般结构是这样的:

  1. 扫描目录并将每个文件所需的详细信息加载到 DupInfo 对象中
  2. 计算与其他文件大小匹配的任何文件的 CRC
  3. 显示任何具有匹配大小和 CRC(以及可选的基本目录)的内容,并允许用户检查他们想要删除的内容(手动和使用“检查所有第一个重复项”之类的按钮)。
  4. 删除选定的文件。

我在执行第 3 步时遇到问题。第 1 步和第 2 步中的数据位于 DupInfo 对象列表中。这是类定义。

public class DupInfo
    {
        public string FullName { get; set; }
        public long Size { get; set; }
        public uint? CheckSum { get; set; }
        public string BaseDirectory { get; set; }
        public DupInfo(FileInfo file, Crc32 crc, int level)
        {
            FullName = file.FullName;
            Size = file.Length;
            CheckSum = crc.ComputeChecksum(File.ReadAllBytes(FullName));
            BaseDirectory = FullName.Substring(0,FullName.NthIndexOf("\\",level));
        }
        public DupInfo(FileInfo file, int level)
        {
            FullName = file.FullName;
            Size = file.Length;
            BaseDirectory = FullName.Substring(0, FullName.NthIndexOf("\\", level));
        }

    }

我的问题是:

  1. 将数据从自定义类 (DupInfo) 列表加载到 Listview 对象的最佳方法是什么?

  2. 如果列表视图不是显示我的重复集的最佳工具,那么最好的工具是什么?

【问题讨论】:

    标签: c# wpf listview itemssource


    【解决方案1】:

    我会使用绑定到ObservableCollection<DupInfo> 的DataGrid。

    <Window x:Class="DataGridDupInfoStack.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <DataGrid ItemsSource="{Binding items}">
    
        </DataGrid>
      </Grid>
    </Window>
    

    代码隐藏:

    public partial class MainWindow : Window
    {
        public ObservableCollection<DupInfo> items { get; set; }
    
        public MainWindow()
        {
            InitializeComponent();
            items = new ObservableCollection<DupInfo>();
    
            items.Add(new DupInfo() { BaseDirectory = "Directory1", CheckSum = 0xFF, FullName = "Info1", Size = 100 });
            items.Add(new DupInfo() { BaseDirectory = "Directory2", CheckSum = 0xFE, FullName = "Info2", Size = 150 });
            items.Add(new DupInfo() { BaseDirectory = "Directory2", CheckSum = 0xFD, FullName = "Info3", Size = 200 });
            this.DataContext = this;
    
        }
    }
    

    这是你的 DupInfo 类。我省略了构造函数以更快地处理它。

    public class DupInfo
    {
        public string FullName { get; set; }
        public long Size { get; set; }
        public uint? CheckSum { get; set; }
        public string BaseDirectory { get; set; }
    }
    

    结果:

    更新 1:

    我们没有可用的 AddRange,但为此定义了一个扩展方法:

    public static class ExtensionMethods
    {
        public static void AddRange(this ObservableCollection<DupInfo> value, List<DupInfo> list)
        {
            foreach (var dup in list)
                value.Add(dup);
        }
    }
    

    这是我们的新版本:

    public partial class MainWindow : Window
    {
        public ObservableCollection<DupInfo> items { get; set; }
    
        List<DupInfo> initialList { get; set; }
    
        public MainWindow()
        {
            InitializeComponent();
            items = new ObservableCollection<DupInfo>();
            initialList = new List<DupInfo>();
    
            initialList.Add(new DupInfo() { BaseDirectory = "Directory1", CheckSum = 0xFF, FullName = "Info1", Size = 100 });
            initialList.Add(new DupInfo() { BaseDirectory = "Directory2", CheckSum = 0xFE, FullName = "Info2", Size = 150 });
            initialList.Add(new DupInfo() { BaseDirectory = "Directory2", CheckSum = 0xFD, FullName = "Info3", Size = 200 });
    
            items.AddRange(initialList);
    
            this.DataContext = this;
    
        }
    }
    
    public static class ExtensionMethods
    {
        public static void AddRange(this ObservableCollection<DupInfo> value, List<DupInfo> list)
        {
            foreach (var dup in list)
                value.Add(dup);
        }
    }
    

    所以我们从一个列表中加载我们的元素......我们可以在那里使用一个数组或根据您的需要使用其他任何东西。

    但是如果你改变了我们的引用指向的对象,请注意。在这种情况下,您将不得不使用 DependencyProperty 或实现 INotifyPropertyChanged。

    您的财产将如下所示:

        public  ObservableCollection<DupInfo> items
        {
            get { return ( ObservableCollection<DupInfo>)GetValue(itemsProperty); }
            set { SetValue(itemsProperty, value); }
        }
    
        // Using a DependencyProperty as the backing store for items.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty itemsProperty =
            DependencyProperty.Register("items", typeof( ObservableCollection<DupInfo>), typeof(MainWindow), new PropertyMetadata(null));
    

    更新 2:

    XAML:

    <Window x:Class="DataGridDupInfoStack.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel>
            <DataGrid ItemsSource="{Binding items}" AutoGenerateColumns="False" CanUserAddRows="False">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Full Name" Binding="{Binding FullName}" />
                    <DataGridTextColumn Header="Size" Binding="{Binding Size}" />
                    <DataGridTextColumn Header="CheckSum" Binding="{Binding CheckSum}" />
                    <DataGridTextColumn Header="BaseDirectory" Binding="{Binding BaseDirectory}" />
                    <DataGridTemplateColumn Header="Mark for deletion">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <CheckBox IsChecked="{Binding Path=ToDelete, UpdateSourceTrigger=PropertyChanged}" />
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
            </DataGrid>
            <Button Content="Delete" Click="btnDelete_Click"/>
        </StackPanel>
    </Grid>
    </Window>
    

    代码隐藏:

    public partial class MainWindow : Window
    {
    
    
        public ObservableCollection<DupInfo> items
        {
            get { return (ObservableCollection<DupInfo>)GetValue(itemsProperty); }
            set { SetValue(itemsProperty, value); }
        }
    
        // Using a DependencyProperty as the backing store for items.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty itemsProperty =
            DependencyProperty.Register("items", typeof(ObservableCollection<DupInfo>), typeof(MainWindow), new PropertyMetadata(null));
    
    
    
        List<DupInfo> initialList { get; set; }
    
        public MainWindow()
        {
            InitializeComponent();
            items = new ObservableCollection<DupInfo>();
            initialList = new List<DupInfo>();
    
            initialList.Add(new DupInfo() { BaseDirectory = "Directory1", CheckSum = 0xFF, FullName = "Info1", Size = 100 });
            initialList.Add(new DupInfo() { BaseDirectory = "Directory2", CheckSum = 0xFE, FullName = "Info2", Size = 150 });
            initialList.Add(new DupInfo() { BaseDirectory = "Directory2", CheckSum = 0xFD, FullName = "Info3", Size = 200 });
    
            items.AddRange(initialList);
    
            this.DataContext = this;
        }
    
    
        private void btnDelete_Click(object sender, RoutedEventArgs e)
        {
            foreach (var dup in items.ToList())
            {
                if (dup.ToDelete)
                {
                    items.Remove(dup);
                }
            }
        }
    }
    
    public static class ExtensionMethods
    {
        public static void AddRange(this ObservableCollection<DupInfo> value, List<DupInfo> list)
        {
            foreach (var dup in list)
                value.Add(dup);
        }
    }
    

    还有你更新的 DupInfo 类:

    public class DupInfo : INotifyPropertyChanged
    {
        private bool _ToDelete;
    
        public bool ToDelete
        {
            get { return _ToDelete; }
            set
            {
                _ToDelete = value;
                PropertyChanged(this, new PropertyChangedEventArgs("ToDelete"));
            }
        }
    
        public string FullName { get; set; }
        public long Size { get; set; }
        public uint? CheckSum { get; set; }
        public string BaseDirectory { get; set; }
    
        public event PropertyChangedEventHandler PropertyChanged = delegate { };
    }
    

    就是这样。祝你好运!

    【讨论】:

    • 谢谢 Olaru,我喜欢这个主意。我想知道如何将我的 DupInfo 列表转换为“项目”对象。是否有适用于 ObservableCollection 的 addrange 或 copyto 方法?或者我可以设置一个 ItemsSource 等于什么。我应该将项目设置为等于 LINQ 查询以转换数据吗?
    • 其实多看你的代码,我觉得我理解错了。看起来它不需要任何转换,但会直接显示来自 DupInfo 对象的 DupInfo 字段。那是对的吗?如果是这样,我如何添加整个 dupInfos 列表?我可以使用 AddRange() 来做到这一点吗?
    • @KalevMaricq DataGrid 有一个属性名称 AutoGenerateColumns,默认情况下为 true。如果你保持这样,你将不需要其他转换。但是,如果您想为列定义模板,请将其设置为 false 并在此处查看 wpf-tutorial.com/datagrid-control/details-row 以了解如何定义 DataGridTemplateColumn。
    • @KalevMaricq 是的,AddRange 扩展应该为您完成这项工作。
    • 谢谢。我会尝试走这条路。如何添加复选框以便用户可以指示要删除哪些文件?
    猜你喜欢
    • 2018-05-16
    • 1970-01-01
    • 1970-01-01
    • 2017-03-21
    • 2015-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多