Selectively Coloring Text in Richtextbox

File System TreeView

If you wanted to stick with the strings something like this would work...

TreeNode root = new TreeNode();
TreeNode node = root;
treeView1.Nodes.Add(root);

foreach (string filePath in myList) // myList is your list of paths
{
node = root;
foreach (string pathBits in filePath.Split('/'))
{
node = AddNode(node, pathBits);
}
}

private TreeNode AddNode(TreeNode node, string key)
{
if (node.Nodes.ContainsKey(key))
{
return node.Nodes[key];
}
else
{
return node.Nodes.Add(key, key);
}
}

Populate TreeView with file system directory structure

Option #1: Recursive approach:

private void ListDirectory(TreeView treeView, string path)
{
treeView.Nodes.Clear();
var rootDirectoryInfo = new DirectoryInfo(path);
treeView.Nodes.Add(CreateDirectoryNode(rootDirectoryInfo));
}

private static TreeNode CreateDirectoryNode(DirectoryInfo directoryInfo)
{
var directoryNode = new TreeNode(directoryInfo.Name);
foreach (var directory in directoryInfo.GetDirectories())
directoryNode.Nodes.Add(CreateDirectoryNode(directory));
foreach (var file in directoryInfo.GetFiles())
directoryNode.Nodes.Add(new TreeNode(file.Name));
return directoryNode;
}

Option #2: Non-recursive approach:

private static void ListDirectory(TreeView treeView, string path)
{
treeView.Nodes.Clear();

var stack = new Stack<TreeNode>();
var rootDirectory = new DirectoryInfo(path);
var node = new TreeNode(rootDirectory.Name) { Tag = rootDirectory };
stack.Push(node);

while (stack.Count > 0)
{
var currentNode = stack.Pop();
var directoryInfo = (DirectoryInfo)currentNode.Tag;
foreach (var directory in directoryInfo.GetDirectories())
{
var childDirectoryNode = new TreeNode(directory.Name) { Tag = directory };
currentNode.Nodes.Add(childDirectoryNode);
stack.Push(childDirectoryNode);
}
foreach (var file in directoryInfo.GetFiles())
currentNode.Nodes.Add(new TreeNode(file.Name));
}

treeView.Nodes.Add(node);
}

Using Tree View in Java to implement a view of a filesystem with hierarchy

I have done it this way. You may modify it according to your needs:

private void createTreeView(String dirPath) {
TreeItem<Object> tree = new TreeItem<>(dirPath.substring(dirPath.lastIndexOf(File.separator) + 1), new ImageView(icon));
List<TreeItem<Object>> dirs = new ArrayList<>();
try {
DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get(dirPath));
for (Path path : directoryStream) {
if (Files.isDirectory(path)) {
String pathString = path.toString();
TreeItem<Object> subDirectory = new TreeItem<>(pathString.substring(pathString.lastIndexOf(File.separator) + 1), new ImageView(icon));
getSubLeafs(path, subDirectory);
dirs.add(subDirectory);
}
}

tree.getChildren().addAll(dirs);
} catch (IOException e) {
e.printStackTrace();
}

treeView.getSelectionModel().selectedItemProperty().addListener((obs, oldVal, newVal) -> {
imageNumber = 1;
StringBuilder pathBuilder = new StringBuilder();
for (TreeItem<String> item = (TreeItem<String>) treeView.getSelectionModel().getSelectedItem(); item != null; item = item.getParent()) {

pathBuilder.insert(0, item.getValue());
pathBuilder.insert(0, "/");
}
String path = pathBuilder.toString();
populateImageView(path.substring(1) + "/");
});

tree.setExpanded(true);
treeView.setRoot(tree);
treeView.setShowRoot(true);
}

private void getSubLeafs(Path subPath, TreeItem<Object> parent) {
try {
DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get(subPath.toString()));
for (Path subDir : directoryStream) {
if (Files.isDirectory(subDir)) {
String subTree = subDir.toString();
TreeItem<Object> subLeafs = new TreeItem<>(subTree, new ImageView(icon));
subLeafs.setValue(subTree.substring(subTree.lastIndexOf(File.separator) + 1));
getSubLeafs(subDir, subLeafs);
parent.getChildren().add(subLeafs);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}

How to display all files under folders in treeview

Change the code in the try block (from: List Drives and Folders in a TreeView Using C#) as following:

EDIT:

Added following code, because the files of the root-directory were ignored:

//add files of rootdirectory
DirectoryInfo rootDir = new DirectoryInfo(e.Node.Tag.ToString());
foreach (var file in rootDir.GetFiles())
{
TreeNode n = new TreeNode(file.Name, 13, 13);
e.Node.Nodes.Add(n);
}

Full class:

private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
if (e.Node.Nodes.Count > 0)
{
if (e.Node.Nodes[0].Text == "..." && e.Node.Nodes[0].Tag == null)
{
e.Node.Nodes.Clear();

//get the list of sub direcotires
string[] dirs = Directory.GetDirectories(e.Node.Tag.ToString());

//add files of rootdirectory
DirectoryInfo rootDir = new DirectoryInfo(e.Node.Tag.ToString());
foreach (var file in rootDir.GetFiles())
{
TreeNode n = new TreeNode(file.Name, 13, 13);
e.Node.Nodes.Add(n);
}

foreach (string dir in dirs)
{
DirectoryInfo di = new DirectoryInfo(dir);
TreeNode node = new TreeNode(di.Name, 0, 1);

try
{
//keep the directory's full path in the tag for use later
node.Tag = dir;

//if the directory has sub directories add the place holder
if (di.GetDirectories().Count() > 0)
node.Nodes.Add(null, "...", 0, 0);

foreach (var file in di.GetFiles())
{
TreeNode n = new TreeNode(file.Name, 13, 13);
node.Nodes.Add(n);
}

}
catch (UnauthorizedAccessException)
{
//display a locked folder icon
node.ImageIndex = 12;
node.SelectedImageIndex = 12;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "DirectoryLister",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
e.Node.Nodes.Add(node);
}
}
}
}
}

This look like following picture:

enter image description here

Populate TreeView with files and directories but without hidden folders and files

If you've based your code on that post, you could use the DirectoryInfo.Attributes property to check for Hidden or System values, for example, so you could let those items out of your TreeView list.

WPF Treeview and databinding a Directory Tree

XAML

<TreeView
ItemsSource="{Binding RootDirectoryItems}"
>
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:UserDirectory}" ItemsSource="{Binding Items}">
<Label Content="{Binding Name}" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:UserFile}">
<Label Content="{Binding Name}" />
</DataTemplate>
</TreeView.Resources>
</TreeView>

RootDirectoryItems is presumed to be a property of the viewmodel, something like this:

public ObservableCollection<Object> RootDirectoryItems { get; } 
= new ObservableCollection<object>();

In the C#, assume the presence of INotifyPropertyChanged boilerplate on all property setters. I added two properties to UserDirectory:

  1. Name, a readonly property which returns just the name segment of DirectoryPath. If DirectoryPath may change at runtime, its setter should call OnPropertyChanged("Name");, so that bindings looking at the Name property will know they need to get the new value. UserFile gained a similar Name property, which comes with the same advice about raising PropertyChanged if that's a possibility.

  2. Items: Again, a readonly property, and you should raise PropertyChanged appropriately if either of the constituent collections changes (handle ICollectionChanged.CollectionChanged, and do likewise in the setters if you have setters). Bindings don't care about the declared type of a property, so it just returns System.Collections.IEnumerable -- it could even return object, and the XAML wouldn't care. But let's be just specific enough, without being so specific as to encourage anybody in C# to try to use the property for anything.

If it were me, I'd almost certainly make UserDirectory and UserFile bare immutable "POCO" classes without INotifyPropertyChanged, and simply repopulate if anything changed on the disk. I might depart from immutability by giving UserDirectory a FileWatcher and having it repopulate itself, if I had some reason to expect directories to change a lot.

So here's the C#:

public class UserDirectory
{
public ObservableCollection<UserFile> Files { get; set; } = new ObservableCollection<UserFile>();
public ObservableCollection<UserDirectory> Subfolders { get; set; } = new ObservableCollection<UserDirectory>();

// Concat demands a non-null argument
public IEnumerable Items { get { return Subfolders?.Cast<Object>().Concat(Files); } }

public String DirectoryPath { get; set; }
public String Name { get { return System.IO.Path.GetFileName(DirectoryPath); } }
}

public class UserFile
{
public String FilePath { get; set; }
public Category Category { get; set; }

public String Name { get { return System.IO.Path.GetFileName(FilePath); } }
}

Your Item class isn't needed, because XAML works by "duck typing".

Here's a simpler variant that also works, because both UserDirectory and UserFile have a Name property, and UserFile's missing Items property is quietly shrugged off.

    <TreeView
ItemsSource="{Binding RootDirectoryItems}"
>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Items}">
<Label Content="{Binding Name}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>


Related Topics



Leave a reply



Submit