将数据加载到Listview(WPF)

3
我正在尝试制作一个重复文件检测器(相关问题:比较相邻列表项)。我的一般结构如下:
  1. 扫描目录并将每个文件所需的详细信息加载到DupInfo对象中
  2. 为与其他文件大小匹配的任何文件计算CRCs
  3. 显示任何具有匹配大小和CRCs(以及可选的基本目录),并允许用户检查他们想要删除哪些文件(手动和使用按钮,如“检查所有第一个重复项”)。
  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. 如果Listview不是显示重复集合的最佳工具,那么最好的工具是什么?

1个回答

1
我会使用一个绑定到 ObservableCollection<DupInfo> 的数据表格。
<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>

Codebehind:

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

结果:

enter image description here

更新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列表转换为“items”对象。是否有一个可以与ObservableCollection一起使用的addrange或copyto方法?或者我可以将ItemsSource设置为某些内容。我应该将项目设置为LINQ查询以转换数据吗? - Kalev Maricq
实际上,经过更多查看你的代码,我认为我误解了。它似乎不需要任何转换,而是直接显示DupInfo对象中的DupInfo字段。是这样吗?如果是这样,那么我如何添加整个dupInfos列表呢?我可以使用AddRange()来实现吗? - Kalev Maricq
@KalevMaricq 是的,那个 AddRange 扩展应该适合你的需求。 - Olaru Mircea
谢谢。我会尝试这种方法。如何添加复选框,以便用户可以指示要删除哪些文件? - Kalev Maricq
谢谢。你知道我需要什么引用来使用ObservableCollection吗?它给了我一个找不到的错误。网上有人提到System.Object,我已经有了,还有WindowsBase,它没有在我的using语句中,但是在我的项目引用中。 - Kalev Maricq
显示剩余2条评论

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