Skip to content

Instantly share code, notes, and snippets.

@JokerMartini
Last active July 5, 2017 14:18
Show Gist options
  • Save JokerMartini/8796f5bfe73f0b6e5822 to your computer and use it in GitHub Desktop.
Save JokerMartini/8796f5bfe73f0b6e5822 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; }
/// <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 searchText;
public string SearchText
{
get
{
return this.searchText;
}
set
{
this.searchText = value;
this.OnPropertyChanged();
this.GetDisplayNodes();
}
}
private bool enableFavorites;
public bool EnableFavorites
{
get
{
return this.enableFavorites;
}
set
{
this.enableFavorites = value;
this.GetDisplayNodes();
}
}
public void GetDisplayNodes()
{
// If filtering is enabled, then we must start filtering.
if (!this.EnableFavorites)
{
// If we are not filtering, then we just reset our root nodes to the original collection.
this.RootNodes = this.initialRootCollection;
return;
}
var favorites = new List<INode>();
// Creates our collection of favorite directories by filtering out all of our nested directories.
foreach (DirectoryNode node in this.RootNodes.OfType<DirectoryNode>())
{
favorites.AddRange(node.GetFavorites());
}
// Add any favorite file nodes that might have been in our root node collection.
// Usually there wouldn't be, but we do this to be safe anyway.
favorites.AddRange(this.RootNodes.OfType<FileNode>().Where(fileNode => fileNode.IsFavorite));
// Replace our root nodes with the filtered results.
this.RootNodes = favorites;
return;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment