提问人:Kalev Maricq 提问时间:6/25/2015 最后编辑:CommunityKalev Maricq 更新时间:6/25/2015 访问量:2497
将数据加载到列表视图 (WPF)
Loading Data into Listview (WPF)
问:
我正在尝试制作一个重复的文件检测器(相关问题:比较相邻列表项)。我的总体结构是这样的:
- 扫描目录并将每个文件所需的详细信息加载到 DupInfo 对象中
- 计算大小与其他文件匹配的任何文件的 CRC
- 显示任何具有匹配大小和 CRC(以及可选的基本目录)的内容,并允许用户检查他们想要删除的内容(手动或使用“检查所有第一个重复项”之类的按钮)。
- 删除所选文件。
我在第 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));
}
}
我的问题是:
将数据从自定义类 (DupInfo) 列表加载到 Listview 对象的最佳方法是什么?
如果 Listview 不是显示重复集的最佳工具,那么最好的工具是什么?
答:
1赞
Olaru Mircea
6/25/2015
#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>
代码隐藏:
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 { };
}
仅此而已。祝你好运!
评论
0赞
Kalev Maricq
6/25/2015
谢谢奥拉鲁,我喜欢这个主意。我想知道如何将我的 DupInfo 列表转换为“items”对象。是否有适用于 ObservableCollection 的 addrange 或 copyto 方法?或者我可以将 ItemsSource 设置为等于某物。我是否应该将项设置为等于转换数据的 LINQ 查询?
0赞
Kalev Maricq
6/25/2015
实际上,在多看了你的代码之后,我想我误解了。看起来它不需要任何转换,但会直接显示 DupInfo 对象中的 DupInfo 字段。这是对的吗?如果是这样,如何添加整个 dupInfos 列表?我可以使用 AddRange() 来做到这一点吗?
0赞
Olaru Mircea
6/25/2015
@KalevMaricq DataGrid 的属性名称为 AutoGenerateColumns,默认情况下为 true。如果你保持这种状态,你就不需要其他转换了。但是,如果要为列定义模板,请将其设置为 false,并在此处查看有关如何定义 DataGridTemplateColumn wpf-tutorial.com/datagrid-control/details-row。
0赞
Olaru Mircea
6/25/2015
@KalevMaricq 是的,AddRange 扩展应该可以为您完成这项工作。
0赞
Kalev Maricq
6/25/2015
谢谢。我会尝试走这条路。如何添加复选框,以便用户可以指示要删除的文件?
下一个:生成数据的最有效排序算法
评论