Loading data into a list (WPF)

I'm trying to create a duplicate file detector (related question: Compare adjacent list items ). My general structure is this:

  • Scan the directory and load the required data for each file into a DupInfo object
  • Calculate CRC for all matching size with another file
  • Display any with appropriate sizes and CRCs (and possibly base directories), and allow users to check what they want to remove (either manually or using a button like "Check all first duplicates").
  • Delete selected files.

I'm having trouble with step 3. My data from steps 1 and 2 is in the list of DupInfo objects. Here is the class definition.

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

    }

      

My question is:

  • What's the best way to load data into a Listview object from a list of custom classes (DupInfo)?

  • If Listview isn't the best tool for displaying my duplicate sets, which is better?

+3


source to share


1 answer


I would use DataGrid binding to 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;

    }
}

      

And this is your DupInfo class. I omitted the constructor to deal with it faster.

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

      

Result:

enter image description here

Update 1:

We don't have an AddRange available, but define an extenstion method for it:

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

      

This is our new version:

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

      



So, we load our items from the list. We can use an array there or whatever as per your need.

But note if you change the object our link points to. In this case, you will have to use DependencyProperty or implement INotifyPropertyChanged.

Your property will look like this:

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

      

Update 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>

      

Codebehind:

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

      

And your updated DupInfo class:

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

      

What about it. Good luck!

+1


source







All Articles