C# ObjectListView 实现树状图与表格显示文件夹内容详解
概述
在C#桌面应用程序开发中,经常需要展示文件系统的树状结构和详细内容。ObjectListView
是一个功能强大的开源.NET控件,它扩展了标准的ListView
控件,提供了更多高级功能。本文将介绍如何使用ObjectListView
实现树状结构显示文件夹内容,并支持图片预览功能。

环境准备
首先,需要通过NuGet安装必要的依赖包:
Install-Package ObjectListView
核心实现
1. 文件系统数据模型
创建一个表示文件系统项的模型类:
public class MyFileSystemInfo : IEquatable<MyFileSystemInfo>
{
public MyFileSystemInfo(FileSystemInfo fileSystemInfo)
{
if (fileSystemInfo == null) throw new ArgumentNullException("fileSystemInfo");
this.info = fileSystemInfo;
}
public bool IsDirectory { get { return this.AsDirectory != null; } }
public DirectoryInfo AsDirectory { get { return info as DirectoryInfo; } }
public FileInfo AsFile { get { return info as FileInfo; } }
private readonly FileSystemInfo info;
public string Name { get { return info.Name; } }
public string Extension { get { return info.Extension; } }
public DateTime CreationTime { get { return info.CreationTime; } }
public DateTime LastWriteTime { get { return info.LastWriteTime; } }
public string FullName { get { return info.FullName; } }
public FileAttributes Attributes { get { return info.Attributes; } }
public long Length { get { return this.AsFile != null ? this.AsFile.Length : 0; } }
public IEnumerable GetFileSystemInfos()
{
ArrayList children = new ArrayList();
if (this.IsDirectory)
{
foreach (FileSystemInfo x in this.AsDirectory.GetFileSystemInfos())
children.Add(new MyFileSystemInfo(x));
}
return children;
}
// 实现相等性比较接口
public bool Equals(MyFileSystemInfo other)
{
return other != null && Equals(other.info.FullName, this.info.FullName);
}
public override bool Equals(object obj)
{
return Equals(obj as MyFileSystemInfo);
}
public override int GetHashCode()
{
return this.info.FullName.GetHashCode();
}
}
2. 初始化树状列表视图
void InitializeTreeListExample()
{
// 设置树形列表属性
this.treeListView.HierarchicalCheckboxes = true;
this.treeListView.HideSelection = true;
// 设置节点展开判断逻辑
this.treeListView.CanExpandGetter = delegate (object x)
{
return ((MyFileSystemInfo)x).IsDirectory;
};
// 设置获取子节点逻辑
this.treeListView.ChildrenGetter = delegate (object x)
{
MyFileSystemInfo myFileSystemInfo = (MyFileSystemInfo)x;
try
{
return myFileSystemInfo.GetFileSystemInfos();
}
catch (UnauthorizedAccessException ex)
{
MessageBox.Show(ex.Message, "权限错误", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return new ArrayList();
}
};
// 自定义树形连接线样式
TreeListView.TreeRenderer renderer = this.treeListView.TreeColumnRenderer;
renderer.LinePen = new Pen(Color.Firebrick, 0.5f);
renderer.LinePen.DashStyle = DashStyle.Dot;
// 设置系统图标
SysImageListHelper helper = new SysImageListHelper(this.treeListView);
this.treeColumnName.ImageGetter = delegate (object x)
{
return helper.GetImageIndex(((MyFileSystemInfo)x).FullName);
};
// 设置自定义渲染器
this.treeColumnDetail.Renderer = new OperationRenderer();
this.treeColumnDelete.Renderer = new OperationRenderer1();
// 设置文件类型列
this.treeColumnFileType.AspectGetter = delegate (object x)
{
return ShellUtilities.GetFileType(((MyFileSystemInfo)x).FullName);
};
// 加载根节点
string path = "E://Imgs//" + DateTime.Now.ToString("yyyyMMdd");
ArrayList roots = new ArrayList();
roots.Add(new MyFileSystemInfo(new DirectoryInfo(path)));
this.treeListView.Roots = roots;
this.treeListView.Refresh();
SelectAllNodes(); // 选中所有节点
}
3. 自定义列渲染器
实现操作按钮的自定义渲染:
public class OperationRenderer : BaseRenderer
{
private readonly Pen borderPen = new Pen(Color.DarkBlue, 1.5f);
private readonly Brush textBrush = new SolidBrush(Color.White);
private readonly Brush backgroundBrush = new SolidBrush(Color.FromArgb(70, 130, 180));
public override void Render(Graphics g, Rectangle r)
{
var rowData = this.RowObject as MyFileSystemInfo;
if (ShouldShowOperation(rowData))
{
// 绘制按钮背景和边框
g.FillRectangle(backgroundBrush, r);
g.DrawRectangle(borderPen, r.X, r.Y, r.Width - 1, r.Height - 1);
// 绘制文字
StringFormat fmt = new StringFormat
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
};
g.DrawString("详情",
new Font("微软雅黑", 9, FontStyle.Bold),
textBrush,
r,
fmt);
}
else
{
// 清空不满足条件的单元格
using (var clearBrush = new SolidBrush(this.ListView.BackColor))
{
g.FillRectangle(clearBrush, r);
}
}
}
// 条件判断逻辑
private bool ShouldShowOperation(MyFileSystemInfo data)
{
return data.IsDirectory && data.Name != DateTime.Now.ToString("yyyyMMdd");
}
}
4. 图片预览功能
实现点击查看图片详情功能:
private void treeListView_CellClick(object sender, CellClickEventArgs e)
{
if (e.Column == this.treeColumnDetail)
{
// 获取绑定的文件系统对象
var fileInfo = e.Model as MyFileSystemInfo;
if (fileInfo == null) return;
// 清空现有图片
if (images.Count > 0)
{
foreach (var img in images)
{
img.Dispose();
}
images.Clear();
}
// 加载新图片
imagePaths = GetImageFiles(fileInfo.FullName);
images = new List<Image>();
LoadImages();
// 显示图片
for (int i = 0; i < 4; i++)
{
if (images.Count - 1 >= i)
{
DisplayImage(i);
}
else
{
pictureBoxeList[i].Image = defaultImage;
}
}
}
else if (e.Column == this.treeColumnDelete)
{
// 删除操作
var fileInfo = e.Model as MyFileSystemInfo;
if (fileInfo == null) return;
if (Directory.Exists(fileInfo.FullName))
{
try
{
Directory.Delete(fileInfo.FullName, true);
}
catch (Exception ex)
{
MessageBox.Show($"删除失败: {ex.Message}");
}
}
RefreshTreeView();
}
}
// 获取文件夹中的所有图片文件
static List<string> GetImageFiles(string folderPath)
{
List<string> imagePaths = new List<string>();
if (Directory.Exists(folderPath))
{
string[] imageExtensions = { "*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.tiff" };
foreach (var extension in imageExtensions)
{
string[] files = Directory.GetFiles(folderPath, extension, SearchOption.AllDirectories);
imagePaths.AddRange(files);
}
}
return imagePaths;
}
5. 搜索功能
实现按名称搜索文件系统项:
private void BtnSearch_Click(object sender, EventArgs e)
{
ArrayList roots = new ArrayList();
string targetPath = "E://Imgs//" + DateTime.Now.ToString("yyyyMMdd");
if (string.IsNullOrEmpty(TxtCX.Text))
{
roots.Add(new MyFileSystemInfo(new DirectoryInfo(targetPath)));
this.treeListView.Roots = roots;
return;
}
// 获取所有文件系统项
var allEntries = GetAllFileSystemEntries(targetPath);
ArrayList filteredResults = new ArrayList();
// 筛选匹配项
foreach (var entry in allEntries)
{
var myInfo = new MyFileSystemInfo(entry);
if (myInfo.Name.Contains(TxtCX.Text))
{
filteredResults.Add(myInfo);
}
}
// 更新树形视图
if (filteredResults.Count > 0)
{
this.treeListView.Roots = filteredResults;
}
this.treeListView.Refresh();
}
// 递归获取所有文件系统项
private List<FileSystemInfo> GetAllFileSystemEntries(string rootPath)
{
var entries = new List<FileSystemInfo>();
try
{
var rootDir = new DirectoryInfo(rootPath);
entries.Add(rootDir);
// 递归遍历子目录
foreach (var dir in rootDir.EnumerateDirectories("*", SearchOption.AllDirectories))
{
entries.Add(dir);
foreach (var file in dir.EnumerateFiles())
{
entries.Add(file);
}
}
// 添加根目录文件
foreach (var file in rootDir.EnumerateFiles())
{
entries.Add(file);
}
}
catch (Exception ex)
{
Console.WriteLine($"遍历错误: {ex.Message}");
}
return entries;
}
界面设计建议
-
布局设计:
-
使用SplitContainer将界面分为左右两部分
-
左侧放置TreeListView显示文件树
-
右侧放置PictureBox数组用于图片预览
-
-
列配置:
-
名称列:显示文件/文件夹名称和系统图标
-
类型列:显示文件类型描述
-
修改时间列:显示最后修改时间
-
大小列:显示文件大小
-
操作列:放置详情和删除按钮
-
-
交互设计:
-
支持节点展开/折叠
-
支持复选框多选
-
支持点击操作按钮执行相应功能
-
支持搜索过滤
-
总结
通过使用ObjectListView
控件,我们可以轻松实现一个功能丰富的文件浏览器,具备树形结构展示、多选操作、图片预览等高级功能。本文介绍了核心实现方法,包括数据模型设计、树形列表初始化、自定义渲染器、图片预览和搜索功能。
关键点:
-
使用
MyFileSystemInfo
类封装文件系统项 -
通过
CanExpandGetter
和ChildrenGetter
实现树形结构 -
自定义渲染器实现操作按钮
-
递归遍历文件系统实现搜索功能
-
使用PictureBox数组实现多图预览
这种实现方式可以广泛应用于文件管理、图片浏览、资源管理等场景,具有良好的扩展性和用户体验。
希望本文对您理解和使用C# ObjectListView控件有所帮助。如有任何问题,欢迎在评论区留言讨论