Skip to content

Instantly share code, notes, and snippets.

@scionwest
Created October 28, 2015 20:17
Show Gist options
  • Save scionwest/100fd9e78d44b742dc5d to your computer and use it in GitHub Desktop.
Save scionwest/100fd9e78d44b742dc5d to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace DirectoryTree
{
public class DirectoryNode : INode, INotifyPropertyChanged
{
private ObservableCollection<INode> children;
public DirectoryNode(DirectoryInfo directoryInfo)
{
this.Directory = directoryInfo;
this.Children = new ObservableCollection<INode>();
}
public DirectoryNode(DirectoryInfo directoryInfo, DirectoryNode parent) : this(directoryInfo)
{
this.Parent = parent;
}
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Gets the name of the folder associated with this node.
/// </summary>
public string Name => this.Directory.Name;
/// <summary>
/// Gets the path to the directory associated with this node.
/// </summary>
public string Path => this.Directory?.FullName;
/// <summary>
/// Gets the parent directory for this node.
/// </summary>
public DirectoryNode Parent { get; }
/// <summary>
/// Gets the directory that this node represents.
/// </summary>
public DirectoryInfo Directory { get; }
/// <summary>
/// Gets or sets the children nodes that this directory node can have.
/// </summary>
public ObservableCollection<INode> Children
{
get
{
return this.children;
}
set
{
this.children = value;
this.OnPropertyChanged();
}
}
public bool IsFavorite { get; set; }
public IEnumerable<INode> Search(string filename)
{
var searchResults = new List<INode>();
foreach(INode node in this.Children)
{
var directory = node as DirectoryNode;
if (directory != null)
{
searchResults.AddRange(directory.Search(filename));
}
if (node.Name.Contains(filename))
{
searchResults.Add(node);
}
}
return searchResults;
}
/// <summary>
/// Scans the current directory and creates a new collection of children nodes.
/// The Children nodes collection can be filled with EmptyFolderNode, FileNode or DirectoryNode instances.
/// The Children collection will always have at least 1 element within it.
/// </summary>
public Task BuildChildrenNodes(bool buildAllChildrenNodes = false)
{
// Get all of the folders and files in our current directory.
FileInfo[] filesInDirectory = null;
DirectoryInfo[] directoriesWithinDirectory = null;
try
{
filesInDirectory = this.Directory.GetFiles();
directoriesWithinDirectory = this.Directory.GetDirectories();
}
catch(UnauthorizedAccessException)
{
return Task.FromResult(0);
}
// Convert the folders and files into Directory and File nodes and add them to a temporary collection.
var childrenNodes = new List<INode>();
IEnumerable<DirectoryNode> directoryNodes = directoriesWithinDirectory.Select(dir => new DirectoryNode(dir, this));
childrenNodes.AddRange(directoryNodes);
childrenNodes.AddRange(filesInDirectory.Select(file => new FileNode(this, file)));
if (childrenNodes.Count == 0)
{
// If there are no children directories or files, we setup the Children collection to hold
// an single node that represents an empty directory.
this.Children = new ObservableCollection<INode>(new List<INode> { new EmptyFolderNode(this) });
return Task.FromResult(0);
}
this.Children = new ObservableCollection<INode>(childrenNodes);
// If we don't want to lazily load our children, we must pre-load them all.
if (buildAllChildrenNodes)
{
// return our running async process.
return Task.Run(() =>
{
foreach (DirectoryNode directory in this.Children.OfType<DirectoryNode>())
{
directory.BuildChildrenNodes(true);
}
});
}
return Task.FromResult(0);
}
public IEnumerable<INode> GetFavorites()
{
var favorites = new List<INode>();
if (this.IsFavorite)
{
favorites.Add(this);
}
// Get all of the FileNodes in our Children collection that have the IsFavorite bool set to true, and add them
// to the favorites collection.
favorites.AddRange(this.Children.OfType<FileNode>().Where(fileNode => fileNode.IsFavorite));
// Use some nested recursion to loop through each directory in our children, and have those DirectoryNode's return to us their
// collection of favorites.
foreach(DirectoryNode directory in this.Children.OfType<DirectoryNode>())
{
favorites.AddRange(directory.GetFavorites());
}
return favorites;
}
private void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var handler = this.PropertyChanged;
if (handler == null)
{
return;
}
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
private string searchString;
public string SearchContent
{
get
{
return this.searchString;
}
set
{
this.searchString = value;
this.OnPropertyChanged();
this.Filter();
}
}
private void Filter()
{
var searchResults = new List<INode>();
foreach(INode node in this.RootNodes)
{
Directory folder = node as DirectoryNode;
if (folder != null)
{
searchResults.AddRange(folder.Search(this.SearchContent));
}
if (node.Name.Contains(this.SearchContent))
{
searchResults.Add(node);
}
}
this.RootNodes = new ObservableCollection<INode>(searchResults);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment